Add API, CLI and web UI integration for objects
This change adds the API endpoints, the CLI commands and the web UI elements needed to manage objects in GARMs internal storage. This storage system is meant to be used to distribute the garm-agent and as a single source of truth for provider binaries, when we will add the ability for GARM to scale out. Potentially, we can also use this in air gapped systems to distribute the runner binaries for forges that don't have their own internal storage system (like GHES). Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
This commit is contained in:
parent
f66f95baff
commit
6c46cf9be1
138 changed files with 7911 additions and 267 deletions
338
apiserver/controllers/file_object.go
Normal file
338
apiserver/controllers/file_object.go
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
// Copyright 2025 Cloudbase Solutions 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.
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
gErrors "github.com/cloudbase/garm-provider-common/errors"
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
// swagger:route GET /objects objects ListFileObjects
|
||||
//
|
||||
// List file objects.
|
||||
//
|
||||
// Parameters:
|
||||
// + name: tags
|
||||
// description: List of tags to filter by.
|
||||
// type: array
|
||||
// items:
|
||||
// type: string
|
||||
// in: query
|
||||
// required: false
|
||||
// + name: page
|
||||
// description: The page at which to list.
|
||||
// type: integer
|
||||
// in: query
|
||||
// required: false
|
||||
// + name: pageSize
|
||||
// description: Number of items per page.
|
||||
// type: integer
|
||||
// in: query
|
||||
// required: false
|
||||
//
|
||||
// Responses:
|
||||
// 200: FileObjectPaginatedResponse
|
||||
// 400: APIErrorResponse
|
||||
func (a *APIController) ListFileObjects(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var pageLocation int64
|
||||
var pageSize int64 = 25
|
||||
tags := r.URL.Query().Get("tags")
|
||||
pageArg := r.URL.Query().Get("page")
|
||||
pageSizeArg := r.URL.Query().Get("pageSize")
|
||||
|
||||
if pageArg != "" {
|
||||
pageInt, err := strconv.ParseInt(pageArg, 10, 64)
|
||||
if err == nil && pageInt >= 0 {
|
||||
pageLocation = pageInt
|
||||
}
|
||||
}
|
||||
if pageSizeArg != "" {
|
||||
pageSizeInt, err := strconv.ParseInt(pageSizeArg, 10, 64)
|
||||
if err == nil && pageSizeInt >= 0 {
|
||||
pageSize = pageSizeInt
|
||||
}
|
||||
}
|
||||
parsedTags := parseTagsArg(tags)
|
||||
files, err := a.r.ListFileObjects(ctx, uint64(pageLocation), uint64(pageSize), parsedTags)
|
||||
if err != nil {
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(files); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
|
||||
}
|
||||
}
|
||||
|
||||
// swagger:route DELETE /objects/{objectID} objects DeleteFileObject
|
||||
//
|
||||
// Delete a file object.
|
||||
//
|
||||
// Parameters:
|
||||
// + name: objectID
|
||||
// description: The ID of the file object.
|
||||
// type: string
|
||||
// in: path
|
||||
// required: true
|
||||
//
|
||||
// Responses:
|
||||
// default: APIErrorResponse
|
||||
func (a *APIController) DeleteFileObject(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
objectID, err := getObjectIDFromVars(vars)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get object ID", "error", err)
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("invalid objectID: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.r.DeleteFileObject(ctx, objectID); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to delete file object")
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// swagger:route GET /objects/{objectID} objects GetFileObject
|
||||
//
|
||||
// Get a file object.
|
||||
//
|
||||
// Parameters:
|
||||
// + name: objectID
|
||||
// description: The ID of the file object.
|
||||
// type: string
|
||||
// in: path
|
||||
// required: true
|
||||
//
|
||||
// Responses:
|
||||
// 200: FileObject
|
||||
// 400: APIErrorResponse
|
||||
func (a *APIController) GetFileObject(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
objectID, err := getObjectIDFromVars(vars)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get object ID", "error", err)
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("invalid objectID: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
file, err := a.r.GetFileObject(ctx, objectID)
|
||||
if err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get file object")
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(file); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
|
||||
}
|
||||
}
|
||||
|
||||
// swagger:route PUT /objects/{objectID} objects UpdateFileObject
|
||||
//
|
||||
// Update a file object.
|
||||
//
|
||||
// Parameters:
|
||||
// + name: objectID
|
||||
// description: The ID of the file object.
|
||||
// type: string
|
||||
// in: path
|
||||
// required: true
|
||||
// + name: Body
|
||||
// description: Parameters used when updating a file object.
|
||||
// type: UpdateFileObjectParams
|
||||
// in: body
|
||||
// required: true
|
||||
//
|
||||
// Responses:
|
||||
// 200: FileObject
|
||||
// 400: APIErrorResponse
|
||||
func (a *APIController) UpdateFileObject(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
objectID, err := getObjectIDFromVars(vars)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get object ID", "error", err)
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("invalid objectID: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
var param params.UpdateFileObjectParams
|
||||
if err := json.NewDecoder(r.Body).Decode(¶m); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to decode request")
|
||||
handleError(ctx, w, gErrors.ErrBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if len(param.Tags) > 0 {
|
||||
for idx, val := range param.Tags {
|
||||
param.Tags[idx] = strings.ToLower(strings.TrimSpace(val))
|
||||
}
|
||||
}
|
||||
|
||||
file, err := a.r.UpdateFileObject(ctx, objectID, param)
|
||||
if err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to get file object")
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(file); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIController) CreateFileObject(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
ctx := r.Context()
|
||||
fileName := r.Header.Get("X-File-Name")
|
||||
if fileName == "" {
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("missing X-File-Name header"))
|
||||
return
|
||||
}
|
||||
description := r.Header.Get("X-File-Description")
|
||||
contentLengthStr := r.Header.Get("Content-Length")
|
||||
if contentLengthStr == "" {
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("missing Content-Length header in request"))
|
||||
return
|
||||
}
|
||||
|
||||
tags := r.Header.Get("X-Tags")
|
||||
parsedTags := parseTagsArg(tags)
|
||||
|
||||
fileSize, err := strconv.ParseInt(contentLengthStr, 10, 64)
|
||||
if err != nil {
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("invalid Content-Length"))
|
||||
return
|
||||
}
|
||||
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fileName,
|
||||
Size: fileSize,
|
||||
Tags: parsedTags,
|
||||
}
|
||||
if len(description) > 0 {
|
||||
param.Description = description
|
||||
}
|
||||
|
||||
fileObj, err := a.r.CreateFileObject(ctx, param, r.Body)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to create blob", "error", err)
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(fileObj); err != nil {
|
||||
slog.With(slog.Any("error", err)).ErrorContext(ctx, "failed to encode response")
|
||||
}
|
||||
}
|
||||
|
||||
func (a *APIController) DownloadFileObject(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
objectID, err := getObjectIDFromVars(vars)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get object ID", "error", err)
|
||||
handleError(ctx, w, gErrors.NewBadRequestError("invalid objectID: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
objectDetails, err := a.r.GetFileObject(ctx, objectID)
|
||||
if err != nil {
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
objectHandle, err := a.r.GetFileObjectReader(ctx, objectID)
|
||||
if err != nil {
|
||||
handleError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
defer objectHandle.Close()
|
||||
w.Header().Set("Content-Type", objectDetails.FileType)
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", objectDetails.Name))
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(objectDetails.Size, 10))
|
||||
|
||||
if r.Method == http.MethodHead {
|
||||
return
|
||||
}
|
||||
|
||||
copied, err := io.Copy(w, objectHandle)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to stream data", "error", err)
|
||||
}
|
||||
if copied < objectDetails.Size {
|
||||
slog.WarnContext(ctx, "some data was not streamed", "object_id", objectDetails.ID, "object_size", objectDetails.Size, "streamed_bytes", copied)
|
||||
}
|
||||
}
|
||||
|
||||
func parseTagsArg(tags string) []string {
|
||||
var parsedTags []string
|
||||
foundTag := make(map[string]struct{})
|
||||
if tags != "" {
|
||||
tagList := strings.SplitSeq(tags, ",")
|
||||
for val := range tagList {
|
||||
if val == "" {
|
||||
continue
|
||||
}
|
||||
low := strings.ToLower(strings.TrimSpace(val))
|
||||
if _, ok := foundTag[low]; ok {
|
||||
continue
|
||||
}
|
||||
parsedTags = append(parsedTags, low)
|
||||
foundTag[low] = struct{}{}
|
||||
}
|
||||
}
|
||||
return parsedTags
|
||||
}
|
||||
|
||||
func parseAsUint(val string) (uint, error) {
|
||||
parsedObjID, err := strconv.ParseUint(val, 10, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid object ID; must be a number")
|
||||
}
|
||||
if parsedObjID > math.MaxUint {
|
||||
return 0, fmt.Errorf("the object ID is too large")
|
||||
}
|
||||
return uint(parsedObjID), nil
|
||||
}
|
||||
|
||||
func getObjectIDFromVars(vars map[string]string) (uint, error) {
|
||||
objectID, ok := vars["objectID"]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("no objectID specified")
|
||||
}
|
||||
return parseAsUint(objectID)
|
||||
}
|
||||
|
|
@ -216,6 +216,28 @@ func NewAPIRouter(han *controllers.APIController, authMiddleware, initMiddleware
|
|||
apiRouter.Handle("/metrics-token/", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/metrics-token", http.HandlerFunc(han.MetricsTokenHandler)).Methods("GET", "OPTIONS")
|
||||
|
||||
/////////////
|
||||
// Objects //
|
||||
/////////////
|
||||
// List objects
|
||||
apiRouter.Handle("/objects/", http.HandlerFunc(han.ListFileObjects)).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/objects", http.HandlerFunc(han.ListFileObjects)).Methods("GET", "OPTIONS")
|
||||
// Create object
|
||||
apiRouter.Handle("/objects/", http.HandlerFunc(han.CreateFileObject)).Methods("POST", "OPTIONS")
|
||||
apiRouter.Handle("/objects", http.HandlerFunc(han.CreateFileObject)).Methods("POST", "OPTIONS")
|
||||
// Delete object
|
||||
apiRouter.Handle("/objects/{objectID}/", http.HandlerFunc(han.DeleteFileObject)).Methods("DELETE", "OPTIONS")
|
||||
apiRouter.Handle("/objects/{objectID}", http.HandlerFunc(han.DeleteFileObject)).Methods("DELETE", "OPTIONS")
|
||||
// Download object
|
||||
apiRouter.Handle("/objects/{objectID}/download/", http.HandlerFunc(han.DownloadFileObject)).Methods("GET", "OPTIONS", "HEAD")
|
||||
apiRouter.Handle("/objects/{objectID}/download", http.HandlerFunc(han.DownloadFileObject)).Methods("GET", "OPTIONS", "HEAD")
|
||||
// Get object
|
||||
apiRouter.Handle("/objects/{objectID}/", http.HandlerFunc(han.GetFileObject)).Methods("GET", "OPTIONS")
|
||||
apiRouter.Handle("/objects/{objectID}", http.HandlerFunc(han.GetFileObject)).Methods("GET", "OPTIONS")
|
||||
// Update object
|
||||
apiRouter.Handle("/objects/{objectID}/", http.HandlerFunc(han.UpdateFileObject)).Methods("PUT", "OPTIONS")
|
||||
apiRouter.Handle("/objects/{objectID}", http.HandlerFunc(han.UpdateFileObject)).Methods("PUT", "OPTIONS")
|
||||
|
||||
//////////
|
||||
// Jobs //
|
||||
//////////
|
||||
|
|
|
|||
|
|
@ -364,6 +364,34 @@ definitions:
|
|||
import:
|
||||
package: github.com/cloudbase/garm/params
|
||||
alias: garm_params
|
||||
FileObjectPaginatedResponse:
|
||||
type: object
|
||||
x-go-type:
|
||||
type: FileObjectPaginatedResponse
|
||||
import:
|
||||
package: github.com/cloudbase/garm/params
|
||||
alias: garm_params
|
||||
FileObject:
|
||||
type: object
|
||||
x-go-type:
|
||||
type: FileObject
|
||||
import:
|
||||
package: github.com/cloudbase/garm/params
|
||||
alias: garm_params
|
||||
UpdateFileObjectParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
type: UpdateFileObjectParams
|
||||
import:
|
||||
package: github.com/cloudbase/garm/params
|
||||
alias: garm_params
|
||||
CreateFileObjectParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
type: CreateFileObjectParams
|
||||
import:
|
||||
package: github.com/cloudbase/garm/params
|
||||
alias: garm_params
|
||||
Templates:
|
||||
type: array
|
||||
x-go-type:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ definitions:
|
|||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: CreateEnterpriseParams
|
||||
CreateFileObjectParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
import:
|
||||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: CreateFileObjectParams
|
||||
CreateGiteaCredentialsParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
|
|
@ -118,6 +125,20 @@ definitions:
|
|||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: Enterprises
|
||||
FileObject:
|
||||
type: object
|
||||
x-go-type:
|
||||
import:
|
||||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: FileObject
|
||||
FileObjectPaginatedResponse:
|
||||
type: object
|
||||
x-go-type:
|
||||
import:
|
||||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: FileObjectPaginatedResponse
|
||||
ForgeCredentials:
|
||||
type: object
|
||||
x-go-type:
|
||||
|
|
@ -318,6 +339,13 @@ definitions:
|
|||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: UpdateEntityParams
|
||||
UpdateFileObjectParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
import:
|
||||
alias: garm_params
|
||||
package: github.com/cloudbase/garm/params
|
||||
type: UpdateFileObjectParams
|
||||
UpdateGiteaCredentialsParams:
|
||||
type: object
|
||||
x-go-type:
|
||||
|
|
@ -1290,6 +1318,99 @@ paths:
|
|||
summary: Returns a JWT token that can be used to access the metrics endpoint.
|
||||
tags:
|
||||
- metrics-token
|
||||
/objects:
|
||||
get:
|
||||
operationId: ListFileObjects
|
||||
parameters:
|
||||
- description: List of tags to filter by.
|
||||
in: query
|
||||
name: tags
|
||||
type: string
|
||||
- description: The page at which to list.
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: Number of items per page.
|
||||
in: query
|
||||
name: pageSize
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: FileObjectPaginatedResponse
|
||||
schema:
|
||||
$ref: '#/definitions/FileObjectPaginatedResponse'
|
||||
"400":
|
||||
description: APIErrorResponse
|
||||
schema:
|
||||
$ref: '#/definitions/APIErrorResponse'
|
||||
summary: List file objects.
|
||||
tags:
|
||||
- objects
|
||||
/objects/{objectID}:
|
||||
delete:
|
||||
operationId: DeleteFileObject
|
||||
parameters:
|
||||
- description: The ID of the file object.
|
||||
in: path
|
||||
name: objectID
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
default:
|
||||
description: APIErrorResponse
|
||||
schema:
|
||||
$ref: '#/definitions/APIErrorResponse'
|
||||
summary: Delete a file object.
|
||||
tags:
|
||||
- objects
|
||||
get:
|
||||
operationId: GetFileObject
|
||||
parameters:
|
||||
- description: The ID of the file object.
|
||||
in: path
|
||||
name: objectID
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: FileObject
|
||||
schema:
|
||||
$ref: '#/definitions/FileObject'
|
||||
"400":
|
||||
description: APIErrorResponse
|
||||
schema:
|
||||
$ref: '#/definitions/APIErrorResponse'
|
||||
summary: Get a file object.
|
||||
tags:
|
||||
- objects
|
||||
put:
|
||||
operationId: UpdateFileObject
|
||||
parameters:
|
||||
- description: The ID of the file object.
|
||||
in: path
|
||||
name: objectID
|
||||
required: true
|
||||
type: string
|
||||
- description: Parameters used when updating a file object.
|
||||
in: body
|
||||
name: Body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/UpdateFileObjectParams'
|
||||
description: Parameters used when updating a file object.
|
||||
type: object
|
||||
responses:
|
||||
"200":
|
||||
description: FileObject
|
||||
schema:
|
||||
$ref: '#/definitions/FileObject'
|
||||
"400":
|
||||
description: APIErrorResponse
|
||||
schema:
|
||||
$ref: '#/definitions/APIErrorResponse'
|
||||
summary: Update a file object.
|
||||
tags:
|
||||
- objects
|
||||
/organizations:
|
||||
get:
|
||||
operationId: ListOrgs
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/cloudbase/garm/client/jobs"
|
||||
"github.com/cloudbase/garm/client/login"
|
||||
"github.com/cloudbase/garm/client/metrics_token"
|
||||
"github.com/cloudbase/garm/client/objects"
|
||||
"github.com/cloudbase/garm/client/organizations"
|
||||
"github.com/cloudbase/garm/client/pools"
|
||||
"github.com/cloudbase/garm/client/providers"
|
||||
|
|
@ -80,6 +81,7 @@ func New(transport runtime.ClientTransport, formats strfmt.Registry) *GarmAPI {
|
|||
cli.Jobs = jobs.New(transport, formats)
|
||||
cli.Login = login.New(transport, formats)
|
||||
cli.MetricsToken = metrics_token.New(transport, formats)
|
||||
cli.Objects = objects.New(transport, formats)
|
||||
cli.Organizations = organizations.New(transport, formats)
|
||||
cli.Pools = pools.New(transport, formats)
|
||||
cli.Providers = providers.New(transport, formats)
|
||||
|
|
@ -150,6 +152,8 @@ type GarmAPI struct {
|
|||
|
||||
MetricsToken metrics_token.ClientService
|
||||
|
||||
Objects objects.ClientService
|
||||
|
||||
Organizations organizations.ClientService
|
||||
|
||||
Pools pools.ClientService
|
||||
|
|
@ -178,6 +182,7 @@ func (c *GarmAPI) SetTransport(transport runtime.ClientTransport) {
|
|||
c.Jobs.SetTransport(transport)
|
||||
c.Login.SetTransport(transport)
|
||||
c.MetricsToken.SetTransport(transport)
|
||||
c.Objects.SetTransport(transport)
|
||||
c.Organizations.SetTransport(transport)
|
||||
c.Pools.SetTransport(transport)
|
||||
c.Providers.SetTransport(transport)
|
||||
|
|
|
|||
151
client/objects/delete_file_object_parameters.go
Normal file
151
client/objects/delete_file_object_parameters.go
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewDeleteFileObjectParams creates a new DeleteFileObjectParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewDeleteFileObjectParams() *DeleteFileObjectParams {
|
||||
return &DeleteFileObjectParams{
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteFileObjectParamsWithTimeout creates a new DeleteFileObjectParams object
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewDeleteFileObjectParamsWithTimeout(timeout time.Duration) *DeleteFileObjectParams {
|
||||
return &DeleteFileObjectParams{
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteFileObjectParamsWithContext creates a new DeleteFileObjectParams object
|
||||
// with the ability to set a context for a request.
|
||||
func NewDeleteFileObjectParamsWithContext(ctx context.Context) *DeleteFileObjectParams {
|
||||
return &DeleteFileObjectParams{
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeleteFileObjectParamsWithHTTPClient creates a new DeleteFileObjectParams object
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewDeleteFileObjectParamsWithHTTPClient(client *http.Client) *DeleteFileObjectParams {
|
||||
return &DeleteFileObjectParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteFileObjectParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the delete file object operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type DeleteFileObjectParams struct {
|
||||
|
||||
/* ObjectID.
|
||||
|
||||
The ID of the file object.
|
||||
*/
|
||||
ObjectID string
|
||||
|
||||
timeout time.Duration
|
||||
Context context.Context
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the delete file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *DeleteFileObjectParams) WithDefaults() *DeleteFileObjectParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the delete file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *DeleteFileObjectParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the delete file object params
|
||||
func (o *DeleteFileObjectParams) WithTimeout(timeout time.Duration) *DeleteFileObjectParams {
|
||||
o.SetTimeout(timeout)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetTimeout adds the timeout to the delete file object params
|
||||
func (o *DeleteFileObjectParams) SetTimeout(timeout time.Duration) {
|
||||
o.timeout = timeout
|
||||
}
|
||||
|
||||
// WithContext adds the context to the delete file object params
|
||||
func (o *DeleteFileObjectParams) WithContext(ctx context.Context) *DeleteFileObjectParams {
|
||||
o.SetContext(ctx)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetContext adds the context to the delete file object params
|
||||
func (o *DeleteFileObjectParams) SetContext(ctx context.Context) {
|
||||
o.Context = ctx
|
||||
}
|
||||
|
||||
// WithHTTPClient adds the HTTPClient to the delete file object params
|
||||
func (o *DeleteFileObjectParams) WithHTTPClient(client *http.Client) *DeleteFileObjectParams {
|
||||
o.SetHTTPClient(client)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetHTTPClient adds the HTTPClient to the delete file object params
|
||||
func (o *DeleteFileObjectParams) SetHTTPClient(client *http.Client) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
|
||||
// WithObjectID adds the objectID to the delete file object params
|
||||
func (o *DeleteFileObjectParams) WithObjectID(objectID string) *DeleteFileObjectParams {
|
||||
o.SetObjectID(objectID)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetObjectID adds the objectId to the delete file object params
|
||||
func (o *DeleteFileObjectParams) SetObjectID(objectID string) {
|
||||
o.ObjectID = objectID
|
||||
}
|
||||
|
||||
// WriteToRequest writes these params to a swagger request
|
||||
func (o *DeleteFileObjectParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
|
||||
if err := r.SetTimeout(o.timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
|
||||
// path param objectID
|
||||
if err := r.SetPathParam("objectID", o.ObjectID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
106
client/objects/delete_file_object_responses.go
Normal file
106
client/objects/delete_file_object_responses.go
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
apiserver_params "github.com/cloudbase/garm/apiserver/params"
|
||||
)
|
||||
|
||||
// DeleteFileObjectReader is a Reader for the DeleteFileObject structure.
|
||||
type DeleteFileObjectReader struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ReadResponse reads a server response into the received o.
|
||||
func (o *DeleteFileObjectReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
result := NewDeleteFileObjectDefault(response.Code())
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code()/100 == 2 {
|
||||
return result, nil
|
||||
}
|
||||
return nil, result
|
||||
}
|
||||
|
||||
// NewDeleteFileObjectDefault creates a DeleteFileObjectDefault with default headers values
|
||||
func NewDeleteFileObjectDefault(code int) *DeleteFileObjectDefault {
|
||||
return &DeleteFileObjectDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteFileObjectDefault describes a response with status code -1, with default header values.
|
||||
|
||||
APIErrorResponse
|
||||
*/
|
||||
type DeleteFileObjectDefault struct {
|
||||
_statusCode int
|
||||
|
||||
Payload apiserver_params.APIErrorResponse
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this delete file object default response has a 2xx status code
|
||||
func (o *DeleteFileObjectDefault) IsSuccess() bool {
|
||||
return o._statusCode/100 == 2
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this delete file object default response has a 3xx status code
|
||||
func (o *DeleteFileObjectDefault) IsRedirect() bool {
|
||||
return o._statusCode/100 == 3
|
||||
}
|
||||
|
||||
// IsClientError returns true when this delete file object default response has a 4xx status code
|
||||
func (o *DeleteFileObjectDefault) IsClientError() bool {
|
||||
return o._statusCode/100 == 4
|
||||
}
|
||||
|
||||
// IsServerError returns true when this delete file object default response has a 5xx status code
|
||||
func (o *DeleteFileObjectDefault) IsServerError() bool {
|
||||
return o._statusCode/100 == 5
|
||||
}
|
||||
|
||||
// IsCode returns true when this delete file object default response a status code equal to that given
|
||||
func (o *DeleteFileObjectDefault) IsCode(code int) bool {
|
||||
return o._statusCode == code
|
||||
}
|
||||
|
||||
// Code gets the status code for the delete file object default response
|
||||
func (o *DeleteFileObjectDefault) Code() int {
|
||||
return o._statusCode
|
||||
}
|
||||
|
||||
func (o *DeleteFileObjectDefault) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[DELETE /objects/{objectID}][%d] DeleteFileObject default %s", o._statusCode, payload)
|
||||
}
|
||||
|
||||
func (o *DeleteFileObjectDefault) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[DELETE /objects/{objectID}][%d] DeleteFileObject default %s", o._statusCode, payload)
|
||||
}
|
||||
|
||||
func (o *DeleteFileObjectDefault) GetPayload() apiserver_params.APIErrorResponse {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *DeleteFileObjectDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
151
client/objects/get_file_object_parameters.go
Normal file
151
client/objects/get_file_object_parameters.go
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// NewGetFileObjectParams creates a new GetFileObjectParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewGetFileObjectParams() *GetFileObjectParams {
|
||||
return &GetFileObjectParams{
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetFileObjectParamsWithTimeout creates a new GetFileObjectParams object
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewGetFileObjectParamsWithTimeout(timeout time.Duration) *GetFileObjectParams {
|
||||
return &GetFileObjectParams{
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetFileObjectParamsWithContext creates a new GetFileObjectParams object
|
||||
// with the ability to set a context for a request.
|
||||
func NewGetFileObjectParamsWithContext(ctx context.Context) *GetFileObjectParams {
|
||||
return &GetFileObjectParams{
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetFileObjectParamsWithHTTPClient creates a new GetFileObjectParams object
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewGetFileObjectParamsWithHTTPClient(client *http.Client) *GetFileObjectParams {
|
||||
return &GetFileObjectParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
GetFileObjectParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the get file object operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type GetFileObjectParams struct {
|
||||
|
||||
/* ObjectID.
|
||||
|
||||
The ID of the file object.
|
||||
*/
|
||||
ObjectID string
|
||||
|
||||
timeout time.Duration
|
||||
Context context.Context
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the get file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetFileObjectParams) WithDefaults() *GetFileObjectParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the get file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *GetFileObjectParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the get file object params
|
||||
func (o *GetFileObjectParams) WithTimeout(timeout time.Duration) *GetFileObjectParams {
|
||||
o.SetTimeout(timeout)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetTimeout adds the timeout to the get file object params
|
||||
func (o *GetFileObjectParams) SetTimeout(timeout time.Duration) {
|
||||
o.timeout = timeout
|
||||
}
|
||||
|
||||
// WithContext adds the context to the get file object params
|
||||
func (o *GetFileObjectParams) WithContext(ctx context.Context) *GetFileObjectParams {
|
||||
o.SetContext(ctx)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetContext adds the context to the get file object params
|
||||
func (o *GetFileObjectParams) SetContext(ctx context.Context) {
|
||||
o.Context = ctx
|
||||
}
|
||||
|
||||
// WithHTTPClient adds the HTTPClient to the get file object params
|
||||
func (o *GetFileObjectParams) WithHTTPClient(client *http.Client) *GetFileObjectParams {
|
||||
o.SetHTTPClient(client)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetHTTPClient adds the HTTPClient to the get file object params
|
||||
func (o *GetFileObjectParams) SetHTTPClient(client *http.Client) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
|
||||
// WithObjectID adds the objectID to the get file object params
|
||||
func (o *GetFileObjectParams) WithObjectID(objectID string) *GetFileObjectParams {
|
||||
o.SetObjectID(objectID)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetObjectID adds the objectId to the get file object params
|
||||
func (o *GetFileObjectParams) SetObjectID(objectID string) {
|
||||
o.ObjectID = objectID
|
||||
}
|
||||
|
||||
// WriteToRequest writes these params to a swagger request
|
||||
func (o *GetFileObjectParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
|
||||
if err := r.SetTimeout(o.timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
|
||||
// path param objectID
|
||||
if err := r.SetPathParam("objectID", o.ObjectID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
179
client/objects/get_file_object_responses.go
Normal file
179
client/objects/get_file_object_responses.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
apiserver_params "github.com/cloudbase/garm/apiserver/params"
|
||||
garm_params "github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
// GetFileObjectReader is a Reader for the GetFileObject structure.
|
||||
type GetFileObjectReader struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ReadResponse reads a server response into the received o.
|
||||
func (o *GetFileObjectReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
switch response.Code() {
|
||||
case 200:
|
||||
result := NewGetFileObjectOK()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
case 400:
|
||||
result := NewGetFileObjectBadRequest()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
default:
|
||||
return nil, runtime.NewAPIError("[GET /objects/{objectID}] GetFileObject", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
// NewGetFileObjectOK creates a GetFileObjectOK with default headers values
|
||||
func NewGetFileObjectOK() *GetFileObjectOK {
|
||||
return &GetFileObjectOK{}
|
||||
}
|
||||
|
||||
/*
|
||||
GetFileObjectOK describes a response with status code 200, with default header values.
|
||||
|
||||
FileObject
|
||||
*/
|
||||
type GetFileObjectOK struct {
|
||||
Payload garm_params.FileObject
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get file object o k response has a 2xx status code
|
||||
func (o *GetFileObjectOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get file object o k response has a 3xx status code
|
||||
func (o *GetFileObjectOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get file object o k response has a 4xx status code
|
||||
func (o *GetFileObjectOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get file object o k response has a 5xx status code
|
||||
func (o *GetFileObjectOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get file object o k response a status code equal to that given
|
||||
func (o *GetFileObjectOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
// Code gets the status code for the get file object o k response
|
||||
func (o *GetFileObjectOK) Code() int {
|
||||
return 200
|
||||
}
|
||||
|
||||
func (o *GetFileObjectOK) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects/{objectID}][%d] getFileObjectOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *GetFileObjectOK) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects/{objectID}][%d] getFileObjectOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *GetFileObjectOK) GetPayload() garm_params.FileObject {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *GetFileObjectOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewGetFileObjectBadRequest creates a GetFileObjectBadRequest with default headers values
|
||||
func NewGetFileObjectBadRequest() *GetFileObjectBadRequest {
|
||||
return &GetFileObjectBadRequest{}
|
||||
}
|
||||
|
||||
/*
|
||||
GetFileObjectBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
APIErrorResponse
|
||||
*/
|
||||
type GetFileObjectBadRequest struct {
|
||||
Payload apiserver_params.APIErrorResponse
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this get file object bad request response has a 2xx status code
|
||||
func (o *GetFileObjectBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this get file object bad request response has a 3xx status code
|
||||
func (o *GetFileObjectBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this get file object bad request response has a 4xx status code
|
||||
func (o *GetFileObjectBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this get file object bad request response has a 5xx status code
|
||||
func (o *GetFileObjectBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this get file object bad request response a status code equal to that given
|
||||
func (o *GetFileObjectBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
// Code gets the status code for the get file object bad request response
|
||||
func (o *GetFileObjectBadRequest) Code() int {
|
||||
return 400
|
||||
}
|
||||
|
||||
func (o *GetFileObjectBadRequest) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects/{objectID}][%d] getFileObjectBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *GetFileObjectBadRequest) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects/{objectID}][%d] getFileObjectBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *GetFileObjectBadRequest) GetPayload() apiserver_params.APIErrorResponse {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *GetFileObjectBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
232
client/objects/list_file_objects_parameters.go
Normal file
232
client/objects/list_file_objects_parameters.go
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// NewListFileObjectsParams creates a new ListFileObjectsParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewListFileObjectsParams() *ListFileObjectsParams {
|
||||
return &ListFileObjectsParams{
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewListFileObjectsParamsWithTimeout creates a new ListFileObjectsParams object
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewListFileObjectsParamsWithTimeout(timeout time.Duration) *ListFileObjectsParams {
|
||||
return &ListFileObjectsParams{
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewListFileObjectsParamsWithContext creates a new ListFileObjectsParams object
|
||||
// with the ability to set a context for a request.
|
||||
func NewListFileObjectsParamsWithContext(ctx context.Context) *ListFileObjectsParams {
|
||||
return &ListFileObjectsParams{
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewListFileObjectsParamsWithHTTPClient creates a new ListFileObjectsParams object
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewListFileObjectsParamsWithHTTPClient(client *http.Client) *ListFileObjectsParams {
|
||||
return &ListFileObjectsParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ListFileObjectsParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the list file objects operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type ListFileObjectsParams struct {
|
||||
|
||||
/* Page.
|
||||
|
||||
The page at which to list.
|
||||
*/
|
||||
Page *int64
|
||||
|
||||
/* PageSize.
|
||||
|
||||
Number of items per page.
|
||||
*/
|
||||
PageSize *int64
|
||||
|
||||
/* Tags.
|
||||
|
||||
List of tags to filter by.
|
||||
*/
|
||||
Tags *string
|
||||
|
||||
timeout time.Duration
|
||||
Context context.Context
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the list file objects params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *ListFileObjectsParams) WithDefaults() *ListFileObjectsParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the list file objects params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *ListFileObjectsParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithTimeout(timeout time.Duration) *ListFileObjectsParams {
|
||||
o.SetTimeout(timeout)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetTimeout adds the timeout to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetTimeout(timeout time.Duration) {
|
||||
o.timeout = timeout
|
||||
}
|
||||
|
||||
// WithContext adds the context to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithContext(ctx context.Context) *ListFileObjectsParams {
|
||||
o.SetContext(ctx)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetContext adds the context to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetContext(ctx context.Context) {
|
||||
o.Context = ctx
|
||||
}
|
||||
|
||||
// WithHTTPClient adds the HTTPClient to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithHTTPClient(client *http.Client) *ListFileObjectsParams {
|
||||
o.SetHTTPClient(client)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetHTTPClient adds the HTTPClient to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetHTTPClient(client *http.Client) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
|
||||
// WithPage adds the page to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithPage(page *int64) *ListFileObjectsParams {
|
||||
o.SetPage(page)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPage adds the page to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetPage(page *int64) {
|
||||
o.Page = page
|
||||
}
|
||||
|
||||
// WithPageSize adds the pageSize to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithPageSize(pageSize *int64) *ListFileObjectsParams {
|
||||
o.SetPageSize(pageSize)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPageSize adds the pageSize to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetPageSize(pageSize *int64) {
|
||||
o.PageSize = pageSize
|
||||
}
|
||||
|
||||
// WithTags adds the tags to the list file objects params
|
||||
func (o *ListFileObjectsParams) WithTags(tags *string) *ListFileObjectsParams {
|
||||
o.SetTags(tags)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetTags adds the tags to the list file objects params
|
||||
func (o *ListFileObjectsParams) SetTags(tags *string) {
|
||||
o.Tags = tags
|
||||
}
|
||||
|
||||
// WriteToRequest writes these params to a swagger request
|
||||
func (o *ListFileObjectsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
|
||||
if err := r.SetTimeout(o.timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
|
||||
if o.Page != nil {
|
||||
|
||||
// query param page
|
||||
var qrPage int64
|
||||
|
||||
if o.Page != nil {
|
||||
qrPage = *o.Page
|
||||
}
|
||||
qPage := swag.FormatInt64(qrPage)
|
||||
if qPage != "" {
|
||||
|
||||
if err := r.SetQueryParam("page", qPage); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.PageSize != nil {
|
||||
|
||||
// query param pageSize
|
||||
var qrPageSize int64
|
||||
|
||||
if o.PageSize != nil {
|
||||
qrPageSize = *o.PageSize
|
||||
}
|
||||
qPageSize := swag.FormatInt64(qrPageSize)
|
||||
if qPageSize != "" {
|
||||
|
||||
if err := r.SetQueryParam("pageSize", qPageSize); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.Tags != nil {
|
||||
|
||||
// query param tags
|
||||
var qrTags string
|
||||
|
||||
if o.Tags != nil {
|
||||
qrTags = *o.Tags
|
||||
}
|
||||
qTags := qrTags
|
||||
if qTags != "" {
|
||||
|
||||
if err := r.SetQueryParam("tags", qTags); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
179
client/objects/list_file_objects_responses.go
Normal file
179
client/objects/list_file_objects_responses.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
apiserver_params "github.com/cloudbase/garm/apiserver/params"
|
||||
garm_params "github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
// ListFileObjectsReader is a Reader for the ListFileObjects structure.
|
||||
type ListFileObjectsReader struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ReadResponse reads a server response into the received o.
|
||||
func (o *ListFileObjectsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
switch response.Code() {
|
||||
case 200:
|
||||
result := NewListFileObjectsOK()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
case 400:
|
||||
result := NewListFileObjectsBadRequest()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
default:
|
||||
return nil, runtime.NewAPIError("[GET /objects] ListFileObjects", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
// NewListFileObjectsOK creates a ListFileObjectsOK with default headers values
|
||||
func NewListFileObjectsOK() *ListFileObjectsOK {
|
||||
return &ListFileObjectsOK{}
|
||||
}
|
||||
|
||||
/*
|
||||
ListFileObjectsOK describes a response with status code 200, with default header values.
|
||||
|
||||
FileObjectPaginatedResponse
|
||||
*/
|
||||
type ListFileObjectsOK struct {
|
||||
Payload garm_params.FileObjectPaginatedResponse
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this list file objects o k response has a 2xx status code
|
||||
func (o *ListFileObjectsOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this list file objects o k response has a 3xx status code
|
||||
func (o *ListFileObjectsOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this list file objects o k response has a 4xx status code
|
||||
func (o *ListFileObjectsOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this list file objects o k response has a 5xx status code
|
||||
func (o *ListFileObjectsOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this list file objects o k response a status code equal to that given
|
||||
func (o *ListFileObjectsOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
// Code gets the status code for the list file objects o k response
|
||||
func (o *ListFileObjectsOK) Code() int {
|
||||
return 200
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsOK) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects][%d] listFileObjectsOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsOK) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects][%d] listFileObjectsOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsOK) GetPayload() garm_params.FileObjectPaginatedResponse {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewListFileObjectsBadRequest creates a ListFileObjectsBadRequest with default headers values
|
||||
func NewListFileObjectsBadRequest() *ListFileObjectsBadRequest {
|
||||
return &ListFileObjectsBadRequest{}
|
||||
}
|
||||
|
||||
/*
|
||||
ListFileObjectsBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
APIErrorResponse
|
||||
*/
|
||||
type ListFileObjectsBadRequest struct {
|
||||
Payload apiserver_params.APIErrorResponse
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this list file objects bad request response has a 2xx status code
|
||||
func (o *ListFileObjectsBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this list file objects bad request response has a 3xx status code
|
||||
func (o *ListFileObjectsBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this list file objects bad request response has a 4xx status code
|
||||
func (o *ListFileObjectsBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this list file objects bad request response has a 5xx status code
|
||||
func (o *ListFileObjectsBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this list file objects bad request response a status code equal to that given
|
||||
func (o *ListFileObjectsBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
// Code gets the status code for the list file objects bad request response
|
||||
func (o *ListFileObjectsBadRequest) Code() int {
|
||||
return 400
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsBadRequest) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects][%d] listFileObjectsBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsBadRequest) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[GET /objects][%d] listFileObjectsBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsBadRequest) GetPayload() apiserver_params.APIErrorResponse {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *ListFileObjectsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
222
client/objects/objects_client.go
Normal file
222
client/objects/objects_client.go
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
httptransport "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
// New creates a new objects API client.
|
||||
func New(transport runtime.ClientTransport, formats strfmt.Registry) ClientService {
|
||||
return &Client{transport: transport, formats: formats}
|
||||
}
|
||||
|
||||
// New creates a new objects API client with basic auth credentials.
|
||||
// It takes the following parameters:
|
||||
// - host: http host (github.com).
|
||||
// - basePath: any base path for the API client ("/v1", "/v3").
|
||||
// - scheme: http scheme ("http", "https").
|
||||
// - user: user for basic authentication header.
|
||||
// - password: password for basic authentication header.
|
||||
func NewClientWithBasicAuth(host, basePath, scheme, user, password string) ClientService {
|
||||
transport := httptransport.New(host, basePath, []string{scheme})
|
||||
transport.DefaultAuthentication = httptransport.BasicAuth(user, password)
|
||||
return &Client{transport: transport, formats: strfmt.Default}
|
||||
}
|
||||
|
||||
// New creates a new objects API client with a bearer token for authentication.
|
||||
// It takes the following parameters:
|
||||
// - host: http host (github.com).
|
||||
// - basePath: any base path for the API client ("/v1", "/v3").
|
||||
// - scheme: http scheme ("http", "https").
|
||||
// - bearerToken: bearer token for Bearer authentication header.
|
||||
func NewClientWithBearerToken(host, basePath, scheme, bearerToken string) ClientService {
|
||||
transport := httptransport.New(host, basePath, []string{scheme})
|
||||
transport.DefaultAuthentication = httptransport.BearerToken(bearerToken)
|
||||
return &Client{transport: transport, formats: strfmt.Default}
|
||||
}
|
||||
|
||||
/*
|
||||
Client for objects API
|
||||
*/
|
||||
type Client struct {
|
||||
transport runtime.ClientTransport
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ClientOption may be used to customize the behavior of Client methods.
|
||||
type ClientOption func(*runtime.ClientOperation)
|
||||
|
||||
// ClientService is the interface for Client methods
|
||||
type ClientService interface {
|
||||
DeleteFileObject(params *DeleteFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error
|
||||
|
||||
GetFileObject(params *GetFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetFileObjectOK, error)
|
||||
|
||||
ListFileObjects(params *ListFileObjectsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListFileObjectsOK, error)
|
||||
|
||||
UpdateFileObject(params *UpdateFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateFileObjectOK, error)
|
||||
|
||||
SetTransport(transport runtime.ClientTransport)
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteFileObject deletes a file object
|
||||
*/
|
||||
func (a *Client) DeleteFileObject(params *DeleteFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) error {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewDeleteFileObjectParams()
|
||||
}
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "DeleteFileObject",
|
||||
Method: "DELETE",
|
||||
PathPattern: "/objects/{objectID}",
|
||||
ProducesMediaTypes: []string{"application/json"},
|
||||
ConsumesMediaTypes: []string{"application/json"},
|
||||
Schemes: []string{"http"},
|
||||
Params: params,
|
||||
Reader: &DeleteFileObjectReader{formats: a.formats},
|
||||
AuthInfo: authInfo,
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
_, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
GetFileObject gets a file object
|
||||
*/
|
||||
func (a *Client) GetFileObject(params *GetFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetFileObjectOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewGetFileObjectParams()
|
||||
}
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "GetFileObject",
|
||||
Method: "GET",
|
||||
PathPattern: "/objects/{objectID}",
|
||||
ProducesMediaTypes: []string{"application/json"},
|
||||
ConsumesMediaTypes: []string{"application/json"},
|
||||
Schemes: []string{"http"},
|
||||
Params: params,
|
||||
Reader: &GetFileObjectReader{formats: a.formats},
|
||||
AuthInfo: authInfo,
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
success, ok := result.(*GetFileObjectOK)
|
||||
if ok {
|
||||
return success, nil
|
||||
}
|
||||
// unexpected success response
|
||||
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
|
||||
msg := fmt.Sprintf("unexpected success response for GetFileObject: API contract not enforced by server. Client expected to get an error, but got: %T", result)
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
/*
|
||||
ListFileObjects lists file objects
|
||||
*/
|
||||
func (a *Client) ListFileObjects(params *ListFileObjectsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListFileObjectsOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewListFileObjectsParams()
|
||||
}
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "ListFileObjects",
|
||||
Method: "GET",
|
||||
PathPattern: "/objects",
|
||||
ProducesMediaTypes: []string{"application/json"},
|
||||
ConsumesMediaTypes: []string{"application/json"},
|
||||
Schemes: []string{"http"},
|
||||
Params: params,
|
||||
Reader: &ListFileObjectsReader{formats: a.formats},
|
||||
AuthInfo: authInfo,
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
success, ok := result.(*ListFileObjectsOK)
|
||||
if ok {
|
||||
return success, nil
|
||||
}
|
||||
// unexpected success response
|
||||
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
|
||||
msg := fmt.Sprintf("unexpected success response for ListFileObjects: API contract not enforced by server. Client expected to get an error, but got: %T", result)
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateFileObject updates a file object
|
||||
*/
|
||||
func (a *Client) UpdateFileObject(params *UpdateFileObjectParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*UpdateFileObjectOK, error) {
|
||||
// TODO: Validate the params before sending
|
||||
if params == nil {
|
||||
params = NewUpdateFileObjectParams()
|
||||
}
|
||||
op := &runtime.ClientOperation{
|
||||
ID: "UpdateFileObject",
|
||||
Method: "PUT",
|
||||
PathPattern: "/objects/{objectID}",
|
||||
ProducesMediaTypes: []string{"application/json"},
|
||||
ConsumesMediaTypes: []string{"application/json"},
|
||||
Schemes: []string{"http"},
|
||||
Params: params,
|
||||
Reader: &UpdateFileObjectReader{formats: a.formats},
|
||||
AuthInfo: authInfo,
|
||||
Context: params.Context,
|
||||
Client: params.HTTPClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(op)
|
||||
}
|
||||
|
||||
result, err := a.transport.Submit(op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
success, ok := result.(*UpdateFileObjectOK)
|
||||
if ok {
|
||||
return success, nil
|
||||
}
|
||||
// unexpected success response
|
||||
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
|
||||
msg := fmt.Sprintf("unexpected success response for UpdateFileObject: API contract not enforced by server. Client expected to get an error, but got: %T", result)
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
// SetTransport changes the transport on the client
|
||||
func (a *Client) SetTransport(transport runtime.ClientTransport) {
|
||||
a.transport = transport
|
||||
}
|
||||
173
client/objects/update_file_object_parameters.go
Normal file
173
client/objects/update_file_object_parameters.go
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
cr "github.com/go-openapi/runtime/client"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
garm_params "github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
// NewUpdateFileObjectParams creates a new UpdateFileObjectParams object,
|
||||
// with the default timeout for this client.
|
||||
//
|
||||
// Default values are not hydrated, since defaults are normally applied by the API server side.
|
||||
//
|
||||
// To enforce default values in parameter, use SetDefaults or WithDefaults.
|
||||
func NewUpdateFileObjectParams() *UpdateFileObjectParams {
|
||||
return &UpdateFileObjectParams{
|
||||
timeout: cr.DefaultTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewUpdateFileObjectParamsWithTimeout creates a new UpdateFileObjectParams object
|
||||
// with the ability to set a timeout on a request.
|
||||
func NewUpdateFileObjectParamsWithTimeout(timeout time.Duration) *UpdateFileObjectParams {
|
||||
return &UpdateFileObjectParams{
|
||||
timeout: timeout,
|
||||
}
|
||||
}
|
||||
|
||||
// NewUpdateFileObjectParamsWithContext creates a new UpdateFileObjectParams object
|
||||
// with the ability to set a context for a request.
|
||||
func NewUpdateFileObjectParamsWithContext(ctx context.Context) *UpdateFileObjectParams {
|
||||
return &UpdateFileObjectParams{
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewUpdateFileObjectParamsWithHTTPClient creates a new UpdateFileObjectParams object
|
||||
// with the ability to set a custom HTTPClient for a request.
|
||||
func NewUpdateFileObjectParamsWithHTTPClient(client *http.Client) *UpdateFileObjectParams {
|
||||
return &UpdateFileObjectParams{
|
||||
HTTPClient: client,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateFileObjectParams contains all the parameters to send to the API endpoint
|
||||
|
||||
for the update file object operation.
|
||||
|
||||
Typically these are written to a http.Request.
|
||||
*/
|
||||
type UpdateFileObjectParams struct {
|
||||
|
||||
/* Body.
|
||||
|
||||
Parameters used when updating a file object.
|
||||
*/
|
||||
Body garm_params.UpdateFileObjectParams
|
||||
|
||||
/* ObjectID.
|
||||
|
||||
The ID of the file object.
|
||||
*/
|
||||
ObjectID string
|
||||
|
||||
timeout time.Duration
|
||||
Context context.Context
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// WithDefaults hydrates default values in the update file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *UpdateFileObjectParams) WithDefaults() *UpdateFileObjectParams {
|
||||
o.SetDefaults()
|
||||
return o
|
||||
}
|
||||
|
||||
// SetDefaults hydrates default values in the update file object params (not the query body).
|
||||
//
|
||||
// All values with no default are reset to their zero value.
|
||||
func (o *UpdateFileObjectParams) SetDefaults() {
|
||||
// no default values defined for this parameter
|
||||
}
|
||||
|
||||
// WithTimeout adds the timeout to the update file object params
|
||||
func (o *UpdateFileObjectParams) WithTimeout(timeout time.Duration) *UpdateFileObjectParams {
|
||||
o.SetTimeout(timeout)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetTimeout adds the timeout to the update file object params
|
||||
func (o *UpdateFileObjectParams) SetTimeout(timeout time.Duration) {
|
||||
o.timeout = timeout
|
||||
}
|
||||
|
||||
// WithContext adds the context to the update file object params
|
||||
func (o *UpdateFileObjectParams) WithContext(ctx context.Context) *UpdateFileObjectParams {
|
||||
o.SetContext(ctx)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetContext adds the context to the update file object params
|
||||
func (o *UpdateFileObjectParams) SetContext(ctx context.Context) {
|
||||
o.Context = ctx
|
||||
}
|
||||
|
||||
// WithHTTPClient adds the HTTPClient to the update file object params
|
||||
func (o *UpdateFileObjectParams) WithHTTPClient(client *http.Client) *UpdateFileObjectParams {
|
||||
o.SetHTTPClient(client)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetHTTPClient adds the HTTPClient to the update file object params
|
||||
func (o *UpdateFileObjectParams) SetHTTPClient(client *http.Client) {
|
||||
o.HTTPClient = client
|
||||
}
|
||||
|
||||
// WithBody adds the body to the update file object params
|
||||
func (o *UpdateFileObjectParams) WithBody(body garm_params.UpdateFileObjectParams) *UpdateFileObjectParams {
|
||||
o.SetBody(body)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetBody adds the body to the update file object params
|
||||
func (o *UpdateFileObjectParams) SetBody(body garm_params.UpdateFileObjectParams) {
|
||||
o.Body = body
|
||||
}
|
||||
|
||||
// WithObjectID adds the objectID to the update file object params
|
||||
func (o *UpdateFileObjectParams) WithObjectID(objectID string) *UpdateFileObjectParams {
|
||||
o.SetObjectID(objectID)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetObjectID adds the objectId to the update file object params
|
||||
func (o *UpdateFileObjectParams) SetObjectID(objectID string) {
|
||||
o.ObjectID = objectID
|
||||
}
|
||||
|
||||
// WriteToRequest writes these params to a swagger request
|
||||
func (o *UpdateFileObjectParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
|
||||
|
||||
if err := r.SetTimeout(o.timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
var res []error
|
||||
if err := r.SetBodyParam(o.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// path param objectID
|
||||
if err := r.SetPathParam("objectID", o.ObjectID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
179
client/objects/update_file_object_responses.go
Normal file
179
client/objects/update_file_object_responses.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
package objects
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
apiserver_params "github.com/cloudbase/garm/apiserver/params"
|
||||
garm_params "github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
// UpdateFileObjectReader is a Reader for the UpdateFileObject structure.
|
||||
type UpdateFileObjectReader struct {
|
||||
formats strfmt.Registry
|
||||
}
|
||||
|
||||
// ReadResponse reads a server response into the received o.
|
||||
func (o *UpdateFileObjectReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
|
||||
switch response.Code() {
|
||||
case 200:
|
||||
result := NewUpdateFileObjectOK()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
case 400:
|
||||
result := NewUpdateFileObjectBadRequest()
|
||||
if err := result.readResponse(response, consumer, o.formats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, result
|
||||
default:
|
||||
return nil, runtime.NewAPIError("[PUT /objects/{objectID}] UpdateFileObject", response, response.Code())
|
||||
}
|
||||
}
|
||||
|
||||
// NewUpdateFileObjectOK creates a UpdateFileObjectOK with default headers values
|
||||
func NewUpdateFileObjectOK() *UpdateFileObjectOK {
|
||||
return &UpdateFileObjectOK{}
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateFileObjectOK describes a response with status code 200, with default header values.
|
||||
|
||||
FileObject
|
||||
*/
|
||||
type UpdateFileObjectOK struct {
|
||||
Payload garm_params.FileObject
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this update file object o k response has a 2xx status code
|
||||
func (o *UpdateFileObjectOK) IsSuccess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this update file object o k response has a 3xx status code
|
||||
func (o *UpdateFileObjectOK) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this update file object o k response has a 4xx status code
|
||||
func (o *UpdateFileObjectOK) IsClientError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsServerError returns true when this update file object o k response has a 5xx status code
|
||||
func (o *UpdateFileObjectOK) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this update file object o k response a status code equal to that given
|
||||
func (o *UpdateFileObjectOK) IsCode(code int) bool {
|
||||
return code == 200
|
||||
}
|
||||
|
||||
// Code gets the status code for the update file object o k response
|
||||
func (o *UpdateFileObjectOK) Code() int {
|
||||
return 200
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectOK) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[PUT /objects/{objectID}][%d] updateFileObjectOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectOK) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[PUT /objects/{objectID}][%d] updateFileObjectOK %s", 200, payload)
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectOK) GetPayload() garm_params.FileObject {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUpdateFileObjectBadRequest creates a UpdateFileObjectBadRequest with default headers values
|
||||
func NewUpdateFileObjectBadRequest() *UpdateFileObjectBadRequest {
|
||||
return &UpdateFileObjectBadRequest{}
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateFileObjectBadRequest describes a response with status code 400, with default header values.
|
||||
|
||||
APIErrorResponse
|
||||
*/
|
||||
type UpdateFileObjectBadRequest struct {
|
||||
Payload apiserver_params.APIErrorResponse
|
||||
}
|
||||
|
||||
// IsSuccess returns true when this update file object bad request response has a 2xx status code
|
||||
func (o *UpdateFileObjectBadRequest) IsSuccess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsRedirect returns true when this update file object bad request response has a 3xx status code
|
||||
func (o *UpdateFileObjectBadRequest) IsRedirect() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsClientError returns true when this update file object bad request response has a 4xx status code
|
||||
func (o *UpdateFileObjectBadRequest) IsClientError() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsServerError returns true when this update file object bad request response has a 5xx status code
|
||||
func (o *UpdateFileObjectBadRequest) IsServerError() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCode returns true when this update file object bad request response a status code equal to that given
|
||||
func (o *UpdateFileObjectBadRequest) IsCode(code int) bool {
|
||||
return code == 400
|
||||
}
|
||||
|
||||
// Code gets the status code for the update file object bad request response
|
||||
func (o *UpdateFileObjectBadRequest) Code() int {
|
||||
return 400
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectBadRequest) Error() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[PUT /objects/{objectID}][%d] updateFileObjectBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectBadRequest) String() string {
|
||||
payload, _ := json.Marshal(o.Payload)
|
||||
return fmt.Sprintf("[PUT /objects/{objectID}][%d] updateFileObjectBadRequest %s", 400, payload)
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectBadRequest) GetPayload() apiserver_params.APIErrorResponse {
|
||||
return o.Payload
|
||||
}
|
||||
|
||||
func (o *UpdateFileObjectBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
|
||||
|
||||
// response payload
|
||||
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
585
cmd/garm-cli/cmd/file_object.go
Normal file
585
cmd/garm-cli/cmd/file_object.go
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
// Copyright 2025 Cloudbase Solutions 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.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
apiClientObject "github.com/cloudbase/garm/client/objects"
|
||||
"github.com/cloudbase/garm/cmd/garm-cli/common"
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
var (
|
||||
filePath string
|
||||
fileName string
|
||||
fileObjTags string
|
||||
fileObjDescription string
|
||||
fileObjPage int64
|
||||
fileObjPageSize int64
|
||||
outObjectPath string
|
||||
forceOverwrite bool
|
||||
quietMode bool
|
||||
)
|
||||
|
||||
// progressReader wraps an io.Reader and reports progress
|
||||
type progressReader struct {
|
||||
reader io.Reader
|
||||
total int64
|
||||
current int64
|
||||
lastPrinted int
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func newProgressReader(r io.Reader, total int64) *progressReader {
|
||||
return &progressReader{
|
||||
reader: r,
|
||||
total: total,
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *progressReader) Read(p []byte) (int, error) {
|
||||
n, err := pr.reader.Read(p)
|
||||
pr.mu.Lock()
|
||||
pr.current += int64(n)
|
||||
pr.mu.Unlock()
|
||||
pr.printProgress()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (pr *progressReader) printProgress() {
|
||||
pr.mu.Lock()
|
||||
defer pr.mu.Unlock()
|
||||
|
||||
if pr.total == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
percent := int(float64(pr.current) / float64(pr.total) * 100)
|
||||
|
||||
// Only print every 5% or at 100%
|
||||
if percent != pr.lastPrinted && (percent%5 == 0 || percent == 100) {
|
||||
mb := float64(pr.current) / 1024 / 1024
|
||||
totalMB := float64(pr.total) / 1024 / 1024
|
||||
fmt.Printf("\rUploading: %d%% (%.2f MB / %.2f MB)", percent, mb, totalMB)
|
||||
if percent == 100 {
|
||||
fmt.Println() // New line at completion
|
||||
}
|
||||
pr.lastPrinted = percent
|
||||
}
|
||||
}
|
||||
|
||||
// giteaCredentialsCmd represents the gitea credentials command
|
||||
var fileObjectCmd = &cobra.Command{
|
||||
Use: "object",
|
||||
Short: "Manage simple object storage",
|
||||
Long: `Manage simple object storage.
|
||||
|
||||
This command allows you to use GARM as a simple, private internal-use object storage
|
||||
system streamed to and from the database using blob I/O. The primary goal of this is
|
||||
to allow users to store provider binaries, agent binaries runner tools and any other
|
||||
type of files needed for a functional GARM deployment.
|
||||
|
||||
It is not meant to be used to serve files outside of the needs of GARM.`,
|
||||
Run: nil,
|
||||
}
|
||||
|
||||
var fileObjListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List file objects",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
listReq := apiClientObject.NewListFileObjectsParams()
|
||||
listReq.Tags = &fileObjTags
|
||||
listReq.Page = &fileObjPage
|
||||
listReq.PageSize = &fileObjPageSize
|
||||
response, err := apiCli.Objects.ListFileObjects(listReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatFileObjsList(response.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var fileObjDeleteCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Aliases: []string{"delete", "del", "rm"},
|
||||
Short: "List file objects",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
objID := args[0]
|
||||
|
||||
delReq := apiClientObject.NewDeleteFileObjectParams().WithObjectID(objID)
|
||||
err := apiCli.Objects.DeleteFileObject(delReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var fileObjShowCmd = &cobra.Command{
|
||||
Use: "show",
|
||||
Short: "Show a file object",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
objID := args[0]
|
||||
|
||||
getReq := apiClientObject.NewGetFileObjectParams().WithObjectID(objID)
|
||||
resp, err := apiCli.Objects.GetFileObject(getReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneObject(resp.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var fileObjUpdateCmd = &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update a file object",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
objID := args[0]
|
||||
|
||||
hasChanges := false
|
||||
updateParams := params.UpdateFileObjectParams{}
|
||||
updateReq := apiClientObject.NewUpdateFileObjectParams().WithObjectID(objID)
|
||||
if cmd.Flags().Changed("name") {
|
||||
hasChanges = true
|
||||
updateParams.Name = &fileName
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("tags") && fileObjTags != "" {
|
||||
hasChanges = true
|
||||
updateParams.Tags = strings.Split(fileObjTags, ",")
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("description") {
|
||||
hasChanges = true
|
||||
updateParams.Description = &fileObjDescription
|
||||
}
|
||||
|
||||
if !hasChanges {
|
||||
fmt.Println("no changes made")
|
||||
return nil
|
||||
}
|
||||
|
||||
updateReq.Body = updateParams
|
||||
resp, err := apiCli.Objects.UpdateFileObject(updateReq, authToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
formatOneObject(resp.Payload)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var fileObjCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Aliases: []string{"add", "upload"},
|
||||
Short: "Upload a file to the server",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
if filePath == "" {
|
||||
return fmt.Errorf("missing file path")
|
||||
}
|
||||
stat, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to acces file: %w", err)
|
||||
}
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var tags []string
|
||||
if fileObjTags != "" {
|
||||
tags = strings.Split(fileObjTags, ",")
|
||||
}
|
||||
|
||||
// Wrap file reader with progress tracking
|
||||
progressR := newProgressReader(file, stat.Size())
|
||||
|
||||
// Create request with progress-tracked file stream
|
||||
req, err := rawHTTPClient.NewRequest(http.MethodPost, "/objects/", progressR)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
req.Header.Set("X-File-Name", fileName)
|
||||
if len(fileObjDescription) > 2<<12 {
|
||||
return fmt.Errorf("description is too large (max 8KB)")
|
||||
}
|
||||
if fileObjDescription != "" {
|
||||
req.Header.Set("X-File-Description", fileObjDescription)
|
||||
}
|
||||
if len(tags) > 0 {
|
||||
req.Header.Set("X-Tags", strings.Join(tags, ","))
|
||||
}
|
||||
req.ContentLength = stat.Size()
|
||||
|
||||
// Debug: dump request
|
||||
if debug {
|
||||
// Don't dump body for large uploads
|
||||
b, err2 := httputil.DumpRequestOut(req, false)
|
||||
if err2 != nil {
|
||||
return fmt.Errorf("failed to dump request: %w", err2)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "DEBUG REQUEST:\n%s\n", string(b))
|
||||
}
|
||||
|
||||
// Show initial progress
|
||||
fmt.Printf("Uploading %s (%.2f MB)...\n", fileName, float64(stat.Size())/1024/1024)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR: %v\n", err)
|
||||
}
|
||||
return fmt.Errorf("failed to upload: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Debug: dump response
|
||||
if debug {
|
||||
b, err2 := httputil.DumpResponse(resp, true)
|
||||
if err2 != nil {
|
||||
return fmt.Errorf("failed to dump response: %w", err2)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "DEBUG RESPONSE:\n%s\n", string(b))
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR reading response body: %v\n", err)
|
||||
}
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
// Check for non-2xx status codes
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR: HTTP %d: %s\n", resp.StatusCode, string(data))
|
||||
}
|
||||
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(data))
|
||||
}
|
||||
|
||||
var fileResp params.FileObject
|
||||
if err := json.Unmarshal(data, &fileResp); err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR decoding response: %v\nResponse body: %s\n", err, string(data))
|
||||
}
|
||||
return fmt.Errorf("failed to decode response: %w", err)
|
||||
}
|
||||
formatOneObject(fileResp)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var fileObjDownloadCmd = &cobra.Command{
|
||||
Use: "download",
|
||||
Short: "Download a file from the server",
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
if needsInit {
|
||||
return errNeedsInitError
|
||||
}
|
||||
|
||||
objectID := args[0]
|
||||
|
||||
// Create request for download
|
||||
req, err := rawHTTPClient.NewRequest(http.MethodGet, fmt.Sprintf("/objects/%s/download", objectID), nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
// Debug: dump request
|
||||
if debug {
|
||||
b, err2 := httputil.DumpRequestOut(req, false)
|
||||
if err2 != nil {
|
||||
return fmt.Errorf("failed to dump request: %w", err2)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "DEBUG REQUEST:\n%s\n", string(b))
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR: %v\n", err)
|
||||
}
|
||||
return fmt.Errorf("failed to download: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Debug: dump response headers (not body for large files)
|
||||
if debug {
|
||||
b, err2 := httputil.DumpResponse(resp, false)
|
||||
if err2 != nil {
|
||||
return fmt.Errorf("failed to dump response: %w", err2)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "DEBUG RESPONSE:\n%s\n", string(b))
|
||||
}
|
||||
|
||||
// Check for non-2xx status codes
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
data, _ := io.ReadAll(resp.Body)
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR: HTTP %d: %s\n", resp.StatusCode, string(data))
|
||||
}
|
||||
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(data))
|
||||
}
|
||||
|
||||
// Get filename from Content-Disposition header if not specified
|
||||
filename := outObjectPath
|
||||
if filename == "" {
|
||||
contentDisp := resp.Header.Get("Content-Disposition")
|
||||
if contentDisp != "" {
|
||||
// Parse Content-Disposition header
|
||||
_, params, err := mime.ParseMediaType(contentDisp)
|
||||
if err == nil && params["filename"] != "" {
|
||||
filename = params["filename"]
|
||||
}
|
||||
}
|
||||
if filename == "" {
|
||||
return fmt.Errorf("no output file specified and server did not provide filename")
|
||||
}
|
||||
}
|
||||
|
||||
// Check if path exists
|
||||
if stat, err := os.Stat(filename); err == nil {
|
||||
if stat.IsDir() {
|
||||
return fmt.Errorf("output path is a directory: %s", filename)
|
||||
}
|
||||
if !forceOverwrite {
|
||||
return fmt.Errorf("file already exists: %s (use --force-overwrite to overwrite)", filename)
|
||||
}
|
||||
}
|
||||
|
||||
// Create output file
|
||||
outFile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %w", err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
// Get content length for progress tracking
|
||||
contentLength := resp.ContentLength
|
||||
if contentLength <= 0 {
|
||||
// Try to parse from header if not set
|
||||
contentLengthStr := resp.Header.Get("Content-Length")
|
||||
if contentLengthStr != "" {
|
||||
fmt.Sscanf(contentLengthStr, "%d", &contentLength)
|
||||
}
|
||||
}
|
||||
|
||||
// Show initial progress
|
||||
if !quietMode {
|
||||
if contentLength > 0 {
|
||||
fmt.Printf("Downloading %s (%.2f MB)...\n", filename, float64(contentLength)/1024/1024)
|
||||
} else {
|
||||
fmt.Printf("Downloading %s...\n", filename)
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap reader with progress tracking
|
||||
var reader io.Reader = resp.Body
|
||||
if contentLength > 0 && !quietMode {
|
||||
progressR := newProgressReader(resp.Body, contentLength)
|
||||
// Change progress message for download
|
||||
reader = &downloadProgressReader{progressR}
|
||||
}
|
||||
|
||||
// Copy to file
|
||||
written, err := io.Copy(outFile, reader)
|
||||
if err != nil {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "DEBUG ERROR writing to file: %v\n", err)
|
||||
}
|
||||
return fmt.Errorf("failed to write file: %w", err)
|
||||
}
|
||||
|
||||
if !quietMode {
|
||||
fmt.Printf("Downloaded %s (%.2f MB)\n", filename, float64(written)/1024/1024)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// downloadProgressReader wraps progressReader to change the message
|
||||
type downloadProgressReader struct {
|
||||
*progressReader
|
||||
}
|
||||
|
||||
func (dpr *downloadProgressReader) Read(p []byte) (int, error) {
|
||||
n, err := dpr.reader.Read(p)
|
||||
dpr.mu.Lock()
|
||||
dpr.current += int64(n)
|
||||
dpr.mu.Unlock()
|
||||
dpr.printProgress()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (dpr *downloadProgressReader) printProgress() {
|
||||
dpr.mu.Lock()
|
||||
defer dpr.mu.Unlock()
|
||||
|
||||
if dpr.total == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
percent := int(float64(dpr.current) / float64(dpr.total) * 100)
|
||||
|
||||
// Only print every 5% or at 100%
|
||||
if percent != dpr.lastPrinted && (percent%5 == 0 || percent == 100) {
|
||||
mb := float64(dpr.current) / 1024 / 1024
|
||||
totalMB := float64(dpr.total) / 1024 / 1024
|
||||
fmt.Printf("\rDownloading: %d%% (%.2f MB / %.2f MB)", percent, mb, totalMB)
|
||||
if percent == 100 {
|
||||
fmt.Println() // New line at completion
|
||||
}
|
||||
dpr.lastPrinted = percent
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
fileObjCreateCmd.Flags().StringVar(&fileName, "name", "", "Name of the file")
|
||||
fileObjCreateCmd.Flags().StringVar(&fileObjDescription, "description", "", "A short description for the file")
|
||||
fileObjCreateCmd.Flags().StringVar(&filePath, "path", "", "The path on disk to the file")
|
||||
fileObjCreateCmd.Flags().StringVar(&fileObjTags, "tags", "", "Comma separated tag list (ie: test,binary,os_type=linux,example)")
|
||||
|
||||
fileObjCreateCmd.MarkFlagRequired("name")
|
||||
fileObjCreateCmd.MarkFlagRequired("path")
|
||||
|
||||
fileObjDownloadCmd.Flags().StringVar(&outObjectPath, "out-file", "", "Output file path (optional, defaults to filename from server)")
|
||||
fileObjDownloadCmd.Flags().BoolVar(&forceOverwrite, "force-overwrite", false, "Overwrite existing file")
|
||||
fileObjDownloadCmd.Flags().BoolVarP(&quietMode, "quiet", "q", false, "Suppress download progress output")
|
||||
|
||||
fileObjUpdateCmd.Flags().StringVar(&fileName, "name", "", "New name of the file")
|
||||
fileObjUpdateCmd.Flags().StringVar(&fileObjTags, "tags", "", "Set new tags. The tags are a comma separated list (ie: test,binary,os_type=linux,example)")
|
||||
fileObjUpdateCmd.Flags().StringVar(&fileObjDescription, "description", "", "A short description for the file")
|
||||
|
||||
fileObjListCmd.Flags().StringVar(&fileObjTags, "tags", "", "Comma separated list of tags to use as search items (optional)")
|
||||
fileObjListCmd.Flags().Int64Var(&fileObjPage, "page", 0, "The file object page to display")
|
||||
fileObjListCmd.Flags().Int64Var(&fileObjPageSize, "page-size", 25, "Total number of results per page")
|
||||
|
||||
fileObjectCmd.AddCommand(fileObjCreateCmd)
|
||||
fileObjectCmd.AddCommand(fileObjDownloadCmd)
|
||||
fileObjectCmd.AddCommand(fileObjUpdateCmd)
|
||||
fileObjectCmd.AddCommand(fileObjListCmd)
|
||||
fileObjectCmd.AddCommand(fileObjShowCmd)
|
||||
fileObjectCmd.AddCommand(fileObjDeleteCmd)
|
||||
|
||||
rootCmd.AddCommand(fileObjectCmd)
|
||||
}
|
||||
|
||||
func formatOneObject(fileObj params.FileObject) {
|
||||
if outputFormat == common.OutputFormatJSON {
|
||||
printAsJSON(fileObj)
|
||||
return
|
||||
}
|
||||
t := table.NewWriter()
|
||||
t.Style().Options.SeparateHeader = true
|
||||
header := table.Row{"Field", "Value"}
|
||||
t.AppendHeader(header)
|
||||
t.AppendRow([]interface{}{"ID", fileObj.ID})
|
||||
t.AppendRow([]interface{}{"Name", fileObj.Name})
|
||||
t.AppendRow([]interface{}{"Created At", fileObj.CreatedAt})
|
||||
t.AppendRow([]interface{}{"Updated At", fileObj.UpdatedAt})
|
||||
t.AppendRow([]interface{}{"Size", fileObj.Size})
|
||||
t.AppendRow([]interface{}{"SHA256SUM", fileObj.SHA256})
|
||||
t.AppendRow([]interface{}{"File Type", fileObj.FileType})
|
||||
t.AppendRow([]interface{}{"Description", fileObj.Description})
|
||||
|
||||
if len(fileObj.Tags) > 0 {
|
||||
t.AppendRow([]interface{}{"Tags", strings.Join(fileObj.Tags, ", ")})
|
||||
}
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Number: 1, AutoMerge: true},
|
||||
{Number: 2, AutoMerge: false, WidthMax: 100},
|
||||
})
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
||||
func formatFileObjsList(files params.FileObjectPaginatedResponse) {
|
||||
if outputFormat == common.OutputFormatJSON {
|
||||
printAsJSON(files)
|
||||
return
|
||||
}
|
||||
t := table.NewWriter()
|
||||
// Define column count
|
||||
numCols := 6
|
||||
t.Style().Options.SeparateHeader = true
|
||||
t.Style().Options.SeparateRows = true
|
||||
|
||||
// Page header - fill all columns with the same text
|
||||
pageHeaderText := fmt.Sprintf("Page %d of %d", files.CurrentPage, files.Pages)
|
||||
pageHeader := make(table.Row, numCols)
|
||||
for i := range pageHeader {
|
||||
pageHeader[i] = pageHeaderText
|
||||
}
|
||||
t.AppendHeader(pageHeader, table.RowConfig{
|
||||
AutoMerge: true,
|
||||
AutoMergeAlign: text.AlignCenter,
|
||||
})
|
||||
// Column headers
|
||||
header := table.Row{"ID", "Name", "Size", "Tags", "Created", "Updated"}
|
||||
t.AppendHeader(header)
|
||||
// Right-align numeric columns
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Number: 1, Align: text.AlignRight},
|
||||
{Number: 3, Align: text.AlignRight},
|
||||
})
|
||||
|
||||
for _, val := range files.Results {
|
||||
row := table.Row{val.ID, val.Name, formatSize(val.Size), strings.Join(val.Tags, ", "), val.CreatedAt.Format("2006-01-02 15:04:05"), val.UpdatedAt.Format("2006-01-02 15:04:05")}
|
||||
t.AppendRow(row)
|
||||
}
|
||||
fmt.Println(t.Render())
|
||||
}
|
||||
|
||||
func formatSize(bytes int64) string {
|
||||
const unit = 1024
|
||||
if bytes < unit {
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
div, exp := int64(unit), 0
|
||||
for n := bytes / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
|
||||
}
|
||||
|
|
@ -17,8 +17,10 @@ package cmd
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
openapiRuntimeClient "github.com/go-openapi/runtime/client"
|
||||
|
|
@ -47,6 +49,7 @@ var (
|
|||
poolBalancerType string
|
||||
outputFormat common.OutputFormat = common.OutputFormatTable
|
||||
errNeedsInitError = fmt.Errorf("please log into a garm installation first")
|
||||
rawHTTPClient *rawClient
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
|
|
@ -90,6 +93,19 @@ func initAPIClient(baseURL, token string) {
|
|||
WithSchemes([]string{baseURLParsed.Scheme})
|
||||
apiCli = apiClient.NewHTTPClientWithConfig(nil, transportCfg)
|
||||
authToken = openapiRuntimeClient.BearerToken(token)
|
||||
|
||||
joined, err := url.JoinPath(baseURL, apiClient.DefaultBasePath)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to join base url %s with %s: %s", baseURL, apiClient.DefaultBasePath, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
rawHTTPClient = &rawClient{
|
||||
BaseURL: joined,
|
||||
Token: token,
|
||||
HTTPClient: &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
|
@ -147,3 +150,27 @@ func resolveEnterprise(nameOrID, endpoint string) (string, error) {
|
|||
|
||||
return response.Payload[0].ID, nil
|
||||
}
|
||||
|
||||
type rawClient struct {
|
||||
BaseURL string
|
||||
Token string
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
// NewRequest creates a new HTTP request with auth and proper URL
|
||||
func (c *rawClient) NewRequest(method, path string, body io.Reader) (*http.Request, error) {
|
||||
url, err := url.JoinPath(c.BaseURL, path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to join URL: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add JWT token
|
||||
req.Header.Set("Authorization", "Bearer "+c.Token)
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,9 +346,12 @@ func main() {
|
|||
Handler: handlers.CORS(methodsOk, headersOk, allowedOrigins)(router),
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20, // 1 MB
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
// Increased timeouts to support large file uploads/downloads
|
||||
// ReadTimeout covers the entire request read including body
|
||||
ReadTimeout: 30 * time.Minute,
|
||||
// WriteTimeout covers the entire response write
|
||||
WriteTimeout: 30 * time.Minute,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", srv.Addr)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ package mocks
|
|||
|
||||
import (
|
||||
context "context"
|
||||
io "io"
|
||||
|
||||
garm_provider_commonparams "github.com/cloudbase/garm-provider-common/params"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
params "github.com/cloudbase/garm/params"
|
||||
|
|
@ -403,6 +405,64 @@ func (_c *Store_CreateEntityScaleSet_Call) RunAndReturn(run func(context.Context
|
|||
return _c
|
||||
}
|
||||
|
||||
// CreateFileObject provides a mock function with given fields: ctx, param, reader
|
||||
func (_m *Store) CreateFileObject(ctx context.Context, param params.CreateFileObjectParams, reader io.Reader) (params.FileObject, error) {
|
||||
ret := _m.Called(ctx, param, reader)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateFileObject")
|
||||
}
|
||||
|
||||
var r0 params.FileObject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, params.CreateFileObjectParams, io.Reader) (params.FileObject, error)); ok {
|
||||
return rf(ctx, param, reader)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, params.CreateFileObjectParams, io.Reader) params.FileObject); ok {
|
||||
r0 = rf(ctx, param, reader)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.FileObject)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, params.CreateFileObjectParams, io.Reader) error); ok {
|
||||
r1 = rf(ctx, param, reader)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_CreateFileObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateFileObject'
|
||||
type Store_CreateFileObject_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CreateFileObject is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - param params.CreateFileObjectParams
|
||||
// - reader io.Reader
|
||||
func (_e *Store_Expecter) CreateFileObject(ctx interface{}, param interface{}, reader interface{}) *Store_CreateFileObject_Call {
|
||||
return &Store_CreateFileObject_Call{Call: _e.mock.On("CreateFileObject", ctx, param, reader)}
|
||||
}
|
||||
|
||||
func (_c *Store_CreateFileObject_Call) Run(run func(ctx context.Context, param params.CreateFileObjectParams, reader io.Reader)) *Store_CreateFileObject_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(params.CreateFileObjectParams), args[2].(io.Reader))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_CreateFileObject_Call) Return(fileObjParam params.FileObject, err error) *Store_CreateFileObject_Call {
|
||||
_c.Call.Return(fileObjParam, err)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_CreateFileObject_Call) RunAndReturn(run func(context.Context, params.CreateFileObjectParams, io.Reader) (params.FileObject, error)) *Store_CreateFileObject_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CreateGiteaCredentials provides a mock function with given fields: ctx, param
|
||||
func (_m *Store) CreateGiteaCredentials(ctx context.Context, param params.CreateGiteaCredentialsParams) (params.ForgeCredentials, error) {
|
||||
ret := _m.Called(ctx, param)
|
||||
|
|
@ -1180,6 +1240,53 @@ func (_c *Store_DeleteEntityPool_Call) RunAndReturn(run func(context.Context, pa
|
|||
return _c
|
||||
}
|
||||
|
||||
// DeleteFileObject provides a mock function with given fields: ctx, objID
|
||||
func (_m *Store) DeleteFileObject(ctx context.Context, objID uint) error {
|
||||
ret := _m.Called(ctx, objID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteFileObject")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint) error); ok {
|
||||
r0 = rf(ctx, objID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Store_DeleteFileObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFileObject'
|
||||
type Store_DeleteFileObject_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeleteFileObject is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - objID uint
|
||||
func (_e *Store_Expecter) DeleteFileObject(ctx interface{}, objID interface{}) *Store_DeleteFileObject_Call {
|
||||
return &Store_DeleteFileObject_Call{Call: _e.mock.On("DeleteFileObject", ctx, objID)}
|
||||
}
|
||||
|
||||
func (_c *Store_DeleteFileObject_Call) Run(run func(ctx context.Context, objID uint)) *Store_DeleteFileObject_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_DeleteFileObject_Call) Return(_a0 error) *Store_DeleteFileObject_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_DeleteFileObject_Call) RunAndReturn(run func(context.Context, uint) error) *Store_DeleteFileObject_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// DeleteGiteaCredentials provides a mock function with given fields: ctx, id
|
||||
func (_m *Store) DeleteGiteaCredentials(ctx context.Context, id uint) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
|
@ -2035,6 +2142,63 @@ func (_c *Store_GetEntityPool_Call) RunAndReturn(run func(context.Context, param
|
|||
return _c
|
||||
}
|
||||
|
||||
// GetFileObject provides a mock function with given fields: ctx, objID
|
||||
func (_m *Store) GetFileObject(ctx context.Context, objID uint) (params.FileObject, error) {
|
||||
ret := _m.Called(ctx, objID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetFileObject")
|
||||
}
|
||||
|
||||
var r0 params.FileObject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint) (params.FileObject, error)); ok {
|
||||
return rf(ctx, objID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint) params.FileObject); ok {
|
||||
r0 = rf(ctx, objID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.FileObject)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uint) error); ok {
|
||||
r1 = rf(ctx, objID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_GetFileObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFileObject'
|
||||
type Store_GetFileObject_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetFileObject is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - objID uint
|
||||
func (_e *Store_Expecter) GetFileObject(ctx interface{}, objID interface{}) *Store_GetFileObject_Call {
|
||||
return &Store_GetFileObject_Call{Call: _e.mock.On("GetFileObject", ctx, objID)}
|
||||
}
|
||||
|
||||
func (_c *Store_GetFileObject_Call) Run(run func(ctx context.Context, objID uint)) *Store_GetFileObject_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_GetFileObject_Call) Return(_a0 params.FileObject, _a1 error) *Store_GetFileObject_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_GetFileObject_Call) RunAndReturn(run func(context.Context, uint) (params.FileObject, error)) *Store_GetFileObject_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetForgeEntity provides a mock function with given fields: _a0, entityType, entityID
|
||||
func (_m *Store) GetForgeEntity(_a0 context.Context, entityType params.ForgeEntityType, entityID string) (params.ForgeEntity, error) {
|
||||
ret := _m.Called(_a0, entityType, entityID)
|
||||
|
|
@ -3756,6 +3920,64 @@ func (_c *Store_ListEntityScaleSets_Call) RunAndReturn(run func(context.Context,
|
|||
return _c
|
||||
}
|
||||
|
||||
// ListFileObjects provides a mock function with given fields: ctx, page, pageSize
|
||||
func (_m *Store) ListFileObjects(ctx context.Context, page uint64, pageSize uint64) (params.FileObjectPaginatedResponse, error) {
|
||||
ret := _m.Called(ctx, page, pageSize)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListFileObjects")
|
||||
}
|
||||
|
||||
var r0 params.FileObjectPaginatedResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) (params.FileObjectPaginatedResponse, error)); ok {
|
||||
return rf(ctx, page, pageSize)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64) params.FileObjectPaginatedResponse); ok {
|
||||
r0 = rf(ctx, page, pageSize)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.FileObjectPaginatedResponse)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64) error); ok {
|
||||
r1 = rf(ctx, page, pageSize)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_ListFileObjects_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListFileObjects'
|
||||
type Store_ListFileObjects_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ListFileObjects is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - page uint64
|
||||
// - pageSize uint64
|
||||
func (_e *Store_Expecter) ListFileObjects(ctx interface{}, page interface{}, pageSize interface{}) *Store_ListFileObjects_Call {
|
||||
return &Store_ListFileObjects_Call{Call: _e.mock.On("ListFileObjects", ctx, page, pageSize)}
|
||||
}
|
||||
|
||||
func (_c *Store_ListFileObjects_Call) Run(run func(ctx context.Context, page uint64, pageSize uint64)) *Store_ListFileObjects_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uint64), args[2].(uint64))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_ListFileObjects_Call) Return(_a0 params.FileObjectPaginatedResponse, _a1 error) *Store_ListFileObjects_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_ListFileObjects_Call) RunAndReturn(run func(context.Context, uint64, uint64) (params.FileObjectPaginatedResponse, error)) *Store_ListFileObjects_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListGiteaCredentials provides a mock function with given fields: ctx
|
||||
func (_m *Store) ListGiteaCredentials(ctx context.Context) ([]params.ForgeCredentials, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
|
@ -4392,6 +4614,65 @@ func (_c *Store_LockJob_Call) RunAndReturn(run func(context.Context, int64, stri
|
|||
return _c
|
||||
}
|
||||
|
||||
// OpenFileObjectContent provides a mock function with given fields: ctx, objID
|
||||
func (_m *Store) OpenFileObjectContent(ctx context.Context, objID uint) (io.ReadCloser, error) {
|
||||
ret := _m.Called(ctx, objID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for OpenFileObjectContent")
|
||||
}
|
||||
|
||||
var r0 io.ReadCloser
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint) (io.ReadCloser, error)); ok {
|
||||
return rf(ctx, objID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint) io.ReadCloser); ok {
|
||||
r0 = rf(ctx, objID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(io.ReadCloser)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uint) error); ok {
|
||||
r1 = rf(ctx, objID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_OpenFileObjectContent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenFileObjectContent'
|
||||
type Store_OpenFileObjectContent_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// OpenFileObjectContent is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - objID uint
|
||||
func (_e *Store_Expecter) OpenFileObjectContent(ctx interface{}, objID interface{}) *Store_OpenFileObjectContent_Call {
|
||||
return &Store_OpenFileObjectContent_Call{Call: _e.mock.On("OpenFileObjectContent", ctx, objID)}
|
||||
}
|
||||
|
||||
func (_c *Store_OpenFileObjectContent_Call) Run(run func(ctx context.Context, objID uint)) *Store_OpenFileObjectContent_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_OpenFileObjectContent_Call) Return(_a0 io.ReadCloser, _a1 error) *Store_OpenFileObjectContent_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_OpenFileObjectContent_Call) RunAndReturn(run func(context.Context, uint) (io.ReadCloser, error)) *Store_OpenFileObjectContent_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// PoolInstanceCount provides a mock function with given fields: ctx, poolID
|
||||
func (_m *Store) PoolInstanceCount(ctx context.Context, poolID string) (int64, error) {
|
||||
ret := _m.Called(ctx, poolID)
|
||||
|
|
@ -4449,6 +4730,65 @@ func (_c *Store_PoolInstanceCount_Call) RunAndReturn(run func(context.Context, s
|
|||
return _c
|
||||
}
|
||||
|
||||
// SearchFileObjectByTags provides a mock function with given fields: ctx, tags, page, pageSize
|
||||
func (_m *Store) SearchFileObjectByTags(ctx context.Context, tags []string, page uint64, pageSize uint64) (params.FileObjectPaginatedResponse, error) {
|
||||
ret := _m.Called(ctx, tags, page, pageSize)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SearchFileObjectByTags")
|
||||
}
|
||||
|
||||
var r0 params.FileObjectPaginatedResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, uint64, uint64) (params.FileObjectPaginatedResponse, error)); ok {
|
||||
return rf(ctx, tags, page, pageSize)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, uint64, uint64) params.FileObjectPaginatedResponse); ok {
|
||||
r0 = rf(ctx, tags, page, pageSize)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.FileObjectPaginatedResponse)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, []string, uint64, uint64) error); ok {
|
||||
r1 = rf(ctx, tags, page, pageSize)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_SearchFileObjectByTags_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SearchFileObjectByTags'
|
||||
type Store_SearchFileObjectByTags_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// SearchFileObjectByTags is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - tags []string
|
||||
// - page uint64
|
||||
// - pageSize uint64
|
||||
func (_e *Store_Expecter) SearchFileObjectByTags(ctx interface{}, tags interface{}, page interface{}, pageSize interface{}) *Store_SearchFileObjectByTags_Call {
|
||||
return &Store_SearchFileObjectByTags_Call{Call: _e.mock.On("SearchFileObjectByTags", ctx, tags, page, pageSize)}
|
||||
}
|
||||
|
||||
func (_c *Store_SearchFileObjectByTags_Call) Run(run func(ctx context.Context, tags []string, page uint64, pageSize uint64)) *Store_SearchFileObjectByTags_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].([]string), args[2].(uint64), args[3].(uint64))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_SearchFileObjectByTags_Call) Return(_a0 params.FileObjectPaginatedResponse, _a1 error) *Store_SearchFileObjectByTags_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_SearchFileObjectByTags_Call) RunAndReturn(run func(context.Context, []string, uint64, uint64) (params.FileObjectPaginatedResponse, error)) *Store_SearchFileObjectByTags_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetScaleSetDesiredRunnerCount provides a mock function with given fields: ctx, scaleSetID, desiredRunnerCount
|
||||
func (_m *Store) SetScaleSetDesiredRunnerCount(ctx context.Context, scaleSetID uint, desiredRunnerCount int) error {
|
||||
ret := _m.Called(ctx, scaleSetID, desiredRunnerCount)
|
||||
|
|
@ -4826,6 +5166,64 @@ func (_c *Store_UpdateEntityScaleSet_Call) RunAndReturn(run func(context.Context
|
|||
return _c
|
||||
}
|
||||
|
||||
// UpdateFileObject provides a mock function with given fields: ctx, objID, param
|
||||
func (_m *Store) UpdateFileObject(ctx context.Context, objID uint, param params.UpdateFileObjectParams) (params.FileObject, error) {
|
||||
ret := _m.Called(ctx, objID, param)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateFileObject")
|
||||
}
|
||||
|
||||
var r0 params.FileObject
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint, params.UpdateFileObjectParams) (params.FileObject, error)); ok {
|
||||
return rf(ctx, objID, param)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint, params.UpdateFileObjectParams) params.FileObject); ok {
|
||||
r0 = rf(ctx, objID, param)
|
||||
} else {
|
||||
r0 = ret.Get(0).(params.FileObject)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uint, params.UpdateFileObjectParams) error); ok {
|
||||
r1 = rf(ctx, objID, param)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Store_UpdateFileObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateFileObject'
|
||||
type Store_UpdateFileObject_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UpdateFileObject is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - objID uint
|
||||
// - param params.UpdateFileObjectParams
|
||||
func (_e *Store_Expecter) UpdateFileObject(ctx interface{}, objID interface{}, param interface{}) *Store_UpdateFileObject_Call {
|
||||
return &Store_UpdateFileObject_Call{Call: _e.mock.On("UpdateFileObject", ctx, objID, param)}
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateFileObject_Call) Run(run func(ctx context.Context, objID uint, param params.UpdateFileObjectParams)) *Store_UpdateFileObject_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(uint), args[2].(params.UpdateFileObjectParams))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateFileObject_Call) Return(_a0 params.FileObject, _a1 error) *Store_UpdateFileObject_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Store_UpdateFileObject_Call) RunAndReturn(run func(context.Context, uint, params.UpdateFileObjectParams) (params.FileObject, error)) *Store_UpdateFileObject_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdateGiteaCredentials provides a mock function with given fields: ctx, id, param
|
||||
func (_m *Store) UpdateGiteaCredentials(ctx context.Context, id uint, param params.UpdateGiteaCredentialsParams) (params.ForgeCredentials, error) {
|
||||
ret := _m.Called(ctx, id, param)
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ type FileObjectStore interface {
|
|||
ListFileObjects(ctx context.Context, page, pageSize uint64) (params.FileObjectPaginatedResponse, error)
|
||||
SearchFileObjectByTags(ctx context.Context, tags []string, page, pageSize uint64) (params.FileObjectPaginatedResponse, error)
|
||||
GetFileObject(ctx context.Context, objID uint) (params.FileObject, error)
|
||||
CreateFileObject(ctx context.Context, name string, size int64, tags []string, reader io.Reader) (params.FileObject, error)
|
||||
CreateFileObject(ctx context.Context, param params.CreateFileObjectParams, reader io.Reader) (fileObjParam params.FileObject, err error)
|
||||
UpdateFileObject(ctx context.Context, objID uint, param params.UpdateFileObjectParams) (params.FileObject, error)
|
||||
DeleteFileObject(ctx context.Context, objID uint) error
|
||||
OpenFileObjectContent(ctx context.Context, objID uint) (io.ReadCloser, error)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/mattn/go-sqlite3"
|
||||
"gorm.io/gorm"
|
||||
|
|
@ -18,17 +19,18 @@ import (
|
|||
"github.com/cloudbase/garm/util"
|
||||
)
|
||||
|
||||
func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size int64, tags []string, reader io.Reader) (fileObjParam params.FileObject, err error) {
|
||||
// func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size int64, tags []string, reader io.Reader) (fileObjParam params.FileObject, err error) {
|
||||
func (s *sqlDatabase) CreateFileObject(ctx context.Context, param params.CreateFileObjectParams, reader io.Reader) (fileObjParam params.FileObject, err error) {
|
||||
// Read first 8KB for type detection
|
||||
buffer := make([]byte, 8192)
|
||||
n, _ := io.ReadFull(reader, buffer)
|
||||
fileType := util.DetectFileType(buffer[:n])
|
||||
// Create document with pre-allocated blob
|
||||
|
||||
fileObj := FileObject{
|
||||
Name: name,
|
||||
FileType: fileType,
|
||||
Size: size,
|
||||
Content: make([]byte, size),
|
||||
Name: param.Name,
|
||||
Description: param.Description,
|
||||
FileType: fileType,
|
||||
Size: param.Size,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
|
@ -37,10 +39,19 @@ func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size in
|
|||
}
|
||||
}()
|
||||
|
||||
// Create the file first, without any space allocated for the blob.
|
||||
if err := s.conn.Create(&fileObj).Error; err != nil {
|
||||
return params.FileObject{}, fmt.Errorf("failed to create file object: %w", err)
|
||||
}
|
||||
|
||||
// allocate space for the blob using the zeroblob() function. This will allow us to avoid
|
||||
// having to allocate potentially huge byte arrays in memory and writing that huge blob to
|
||||
// disk.
|
||||
query := fmt.Sprintf(`UPDATE %q SET content = zeroblob(?) WHERE id = ?`, fileObj.TableName())
|
||||
if err := s.conn.Exec(query, param.Size, fileObj.ID).Error; err != nil {
|
||||
return params.FileObject{}, fmt.Errorf("failed to allocate disk space: %w", err)
|
||||
}
|
||||
|
||||
// Stream file to blob and compute SHA256
|
||||
conn, err := s.sqlDB.Conn(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -54,7 +65,7 @@ func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size in
|
|||
|
||||
blob, err := sqliteConn.Blob("main", fileObj.TableName(), "content", int64(fileObj.ID), 1)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to open blob: %w", err)
|
||||
}
|
||||
defer blob.Close()
|
||||
|
||||
|
|
@ -63,14 +74,14 @@ func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size in
|
|||
|
||||
// Write the buffered data first
|
||||
if _, err := blob.Write(buffer[:n]); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to write blob initial buffer: %w", err)
|
||||
}
|
||||
hasher.Write(buffer[:n])
|
||||
|
||||
// Stream the rest with hash computation
|
||||
_, err = io.Copy(io.MultiWriter(blob, hasher), reader)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to write blob: %w", err)
|
||||
}
|
||||
|
||||
// Get final hash
|
||||
|
|
@ -87,7 +98,7 @@ func (s *sqlDatabase) CreateFileObject(ctx context.Context, name string, size in
|
|||
}
|
||||
|
||||
// Create tag entries
|
||||
for _, tag := range tags {
|
||||
for _, tag := range param.Tags {
|
||||
fileObjTag := FileObjectTag{
|
||||
FileObjectID: fileObj.ID,
|
||||
Tag: tag,
|
||||
|
|
@ -129,6 +140,10 @@ func (s *sqlDatabase) UpdateFileObject(_ context.Context, objID uint, param para
|
|||
fileObj.Name = *param.Name
|
||||
}
|
||||
|
||||
if param.Description != nil {
|
||||
fileObj.Description = *param.Description
|
||||
}
|
||||
|
||||
// Update tags if provided
|
||||
if param.Tags != nil {
|
||||
// Delete existing tags
|
||||
|
|
@ -239,9 +254,20 @@ func (s *sqlDatabase) SearchFileObjectByTags(_ context.Context, tags []string, p
|
|||
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
queryPageSize := math.MaxInt
|
||||
if pageSize <= math.MaxInt {
|
||||
queryPageSize = int(pageSize)
|
||||
}
|
||||
|
||||
var queryOffset int
|
||||
if offset <= math.MaxInt {
|
||||
queryOffset = int(offset)
|
||||
} else {
|
||||
return params.FileObjectPaginatedResponse{}, fmt.Errorf("offset excedes max int size: %d", math.MaxInt)
|
||||
}
|
||||
if err := query.
|
||||
Limit(int(pageSize)).
|
||||
Offset(int(offset)).
|
||||
Limit(queryPageSize).
|
||||
Offset(queryOffset).
|
||||
Order("created_at DESC").
|
||||
Omit("content").
|
||||
Find(&fileObjectRes).Error; err != nil {
|
||||
|
|
@ -343,10 +369,23 @@ func (s *sqlDatabase) ListFileObjects(_ context.Context, page, pageSize uint64)
|
|||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
queryPageSize := math.MaxInt
|
||||
if pageSize <= math.MaxInt {
|
||||
queryPageSize = int(pageSize)
|
||||
}
|
||||
|
||||
var queryOffset int
|
||||
if offset <= math.MaxInt {
|
||||
queryOffset = int(offset)
|
||||
} else {
|
||||
return params.FileObjectPaginatedResponse{}, fmt.Errorf("offset excedes max int size: %d", math.MaxInt)
|
||||
}
|
||||
|
||||
var fileObjs []FileObject
|
||||
if err := s.conn.Preload("TagsList").Omit("content").
|
||||
Limit(int(pageSize)).
|
||||
Offset(int(offset)).
|
||||
Limit(queryPageSize).
|
||||
Offset(queryOffset).
|
||||
Order("created_at DESC").
|
||||
Find(&fileObjs).Error; err != nil {
|
||||
return params.FileObjectPaginatedResponse{}, fmt.Errorf("failed to list file objects: %w", err)
|
||||
|
|
@ -384,13 +423,14 @@ func (s *sqlDatabase) sqlFileObjectToCommonParams(obj FileObject) params.FileObj
|
|||
tags[idx] = val.Tag
|
||||
}
|
||||
return params.FileObject{
|
||||
ID: obj.ID,
|
||||
CreatedAt: obj.CreatedAt,
|
||||
UpdatedAt: obj.UpdatedAt,
|
||||
Name: obj.Name,
|
||||
Size: obj.Size,
|
||||
FileType: obj.FileType,
|
||||
SHA256: obj.SHA256,
|
||||
Tags: tags,
|
||||
ID: obj.ID,
|
||||
CreatedAt: obj.CreatedAt,
|
||||
UpdatedAt: obj.UpdatedAt,
|
||||
Name: obj.Name,
|
||||
Size: obj.Size,
|
||||
FileType: obj.FileType,
|
||||
SHA256: obj.SHA256,
|
||||
Description: obj.Description,
|
||||
Tags: tags,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,12 @@ func (s *FileStoreTestSuite) SetupTest() {
|
|||
|
||||
// File 1: Small text file with tags
|
||||
content1 := []byte("Hello, World! This is test file 1.")
|
||||
fileObj1, err := s.Store.CreateFileObject(s.ctx, "test-file-1.txt", int64(len(content1)), []string{"test", "text"}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "test-file-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{"test", "text"},
|
||||
}
|
||||
fileObj1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create test file 1: %s", err))
|
||||
}
|
||||
|
|
@ -75,7 +80,12 @@ func (s *FileStoreTestSuite) SetupTest() {
|
|||
|
||||
// File 2: Binary-like content with different tags
|
||||
content2 := []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00} // PNG header-like
|
||||
fileObj2, err := s.Store.CreateFileObject(s.ctx, "test-image.png", int64(len(content2)), []string{"image", "binary"}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "test-image.png",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{"image", "binary"},
|
||||
}
|
||||
fileObj2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create test file 2: %s", err))
|
||||
}
|
||||
|
|
@ -83,7 +93,12 @@ func (s *FileStoreTestSuite) SetupTest() {
|
|||
|
||||
// File 3: No tags
|
||||
content3 := []byte("File without tags.")
|
||||
fileObj3, err := s.Store.CreateFileObject(s.ctx, "no-tags.txt", int64(len(content3)), []string{}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "no-tags.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{},
|
||||
}
|
||||
fileObj3, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create test file 3: %s", err))
|
||||
}
|
||||
|
|
@ -98,7 +113,12 @@ func (s *FileStoreTestSuite) TestCreateFileObject() {
|
|||
content := []byte("New test file content")
|
||||
tags := []string{"new", "test"}
|
||||
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "new-file.txt", int64(len(content)), tags, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "new-file.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: tags,
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotZero(fileObj.ID)
|
||||
s.Require().Equal("new-file.txt", fileObj.Name)
|
||||
|
|
@ -115,7 +135,12 @@ func (s *FileStoreTestSuite) TestCreateFileObject() {
|
|||
|
||||
func (s *FileStoreTestSuite) TestCreateFileObjectEmpty() {
|
||||
content := []byte{}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "empty-file.txt", 0, []string{}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "empty-file.txt",
|
||||
Size: 0,
|
||||
Tags: []string{},
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotZero(fileObj.ID)
|
||||
s.Require().Equal("empty-file.txt", fileObj.Name)
|
||||
|
|
@ -141,7 +166,12 @@ func (s *FileStoreTestSuite) TestGetFileObjectNotFound() {
|
|||
func (s *FileStoreTestSuite) TestOpenFileObjectContent() {
|
||||
// Create a file with known content
|
||||
content := []byte("Test content for reading")
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "read-test.txt", int64(len(content)), []string{"read"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "read-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"read"},
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Open and read the content
|
||||
|
|
@ -182,7 +212,12 @@ func (s *FileStoreTestSuite) TestListFileObjectsPagination() {
|
|||
// Create more files to test pagination
|
||||
for i := 0; i < 5; i++ {
|
||||
content := []byte(fmt.Sprintf("File %d", i))
|
||||
_, err := s.Store.CreateFileObject(s.ctx, fmt.Sprintf("page-test-%d.txt", i), int64(len(content)), []string{"pagination"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("page-test-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"pagination"},
|
||||
}
|
||||
_, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +348,12 @@ func (s *FileStoreTestSuite) TestUpdateFileObjectEmptyName() {
|
|||
func (s *FileStoreTestSuite) TestDeleteFileObject() {
|
||||
// Create a file to delete
|
||||
content := []byte("To be deleted")
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "delete-me.txt", int64(len(content)), []string{"delete"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "delete-me.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"delete"},
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Delete the file
|
||||
|
|
@ -339,8 +379,12 @@ func (s *FileStoreTestSuite) TestCreateFileObjectLargeContent() {
|
|||
for i := range content {
|
||||
content[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "large-file.bin", int64(size), []string{"large", "binary"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "large-file.bin",
|
||||
Size: int64(size),
|
||||
Tags: []string{"large", "binary"},
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
s.Require().Equal(int64(size), fileObj.Size)
|
||||
|
||||
|
|
@ -357,7 +401,12 @@ func (s *FileStoreTestSuite) TestCreateFileObjectLargeContent() {
|
|||
func (s *FileStoreTestSuite) TestFileObjectImmutableFields() {
|
||||
// Create a file
|
||||
content := []byte("Immutable test content")
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, "immutable-test.txt", int64(len(content)), []string{"original"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "immutable-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"original"},
|
||||
}
|
||||
fileObj, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
originalSize := fileObj.Size
|
||||
|
|
@ -390,19 +439,39 @@ func (s *FileStoreTestSuite) TestFileObjectImmutableFields() {
|
|||
func (s *FileStoreTestSuite) TestSearchFileObjectByTags() {
|
||||
// Create files with specific tags for searching
|
||||
content1 := []byte("File with tag1 and tag2")
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, "search-file-1.txt", int64(len(content1)), []string{"tag1", "tag2"}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "search-file-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content2 := []byte("File with tag1, tag2, and tag3")
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, "search-file-2.txt", int64(len(content2)), []string{"tag1", "tag2", "tag3"}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "search-file-2.txt",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{"tag1", "tag2", "tag3"},
|
||||
}
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content3 := []byte("File with only tag1")
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, "search-file-3.txt", int64(len(content3)), []string{"tag1"}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "search-file-3.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{"tag1"},
|
||||
}
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content4 := []byte("File with tag3 only")
|
||||
_, err = s.Store.CreateFileObject(s.ctx, "search-file-4.txt", int64(len(content4)), []string{"tag3"}, bytes.NewReader(content4))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "search-file-4.txt",
|
||||
Size: int64(len(content4)),
|
||||
Tags: []string{"tag3"},
|
||||
}
|
||||
_, err = s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content4))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Search for files with tag1 - should return 3 files
|
||||
|
|
@ -423,15 +492,30 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTags() {
|
|||
func (s *FileStoreTestSuite) TestSearchFileObjectByTagsMultipleTags() {
|
||||
// Create files with various tag combinations
|
||||
content1 := []byte("File with search1 and search2")
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, "multi-search-1.txt", int64(len(content1)), []string{"search1", "search2"}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "multi-search-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{"search1", "search2"},
|
||||
}
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content2 := []byte("File with search1, search2, and search3")
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, "multi-search-2.txt", int64(len(content2)), []string{"search1", "search2", "search3"}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "multi-search-2.txt",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{"search1", "search2", "search3"},
|
||||
}
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content3 := []byte("File with only search1")
|
||||
_, err = s.Store.CreateFileObject(s.ctx, "multi-search-3.txt", int64(len(content3)), []string{"search1"}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "multi-search-3.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{"search1"},
|
||||
}
|
||||
_, err = s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Search for files with both search1 AND search2 - should return only 2 files
|
||||
|
|
@ -469,7 +553,12 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTagsPagination() {
|
|||
// Create multiple files with the same tag
|
||||
for i := 0; i < 5; i++ {
|
||||
content := []byte(fmt.Sprintf("Pagination test file %d", i))
|
||||
_, err := s.Store.CreateFileObject(s.ctx, fmt.Sprintf("page-search-%d.txt", i), int64(len(content)), []string{"pagination-test"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("page-search-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"pagination-test"},
|
||||
}
|
||||
_, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
|
|
@ -497,7 +586,12 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTagsPagination() {
|
|||
func (s *FileStoreTestSuite) TestSearchFileObjectByTagsDefaultPagination() {
|
||||
// Create a file with a unique tag
|
||||
content := []byte("Default pagination test")
|
||||
_, err := s.Store.CreateFileObject(s.ctx, "default-page-search.txt", int64(len(content)), []string{"default-pagination"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "default-page-search.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"default-pagination"},
|
||||
}
|
||||
_, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Test default values (page 0 should become 1, pageSize 0 should become 20)
|
||||
|
|
@ -511,19 +605,39 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTagsDefaultPagination() {
|
|||
func (s *FileStoreTestSuite) TestSearchFileObjectByTagsAllTagsRequired() {
|
||||
// Test that search requires ALL specified tags (AND logic, not OR)
|
||||
content1 := []byte("Has A and B")
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, "and-test-1.txt", int64(len(content1)), []string{"tagA", "tagB"}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "and-test-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{"tagA", "tagB"},
|
||||
}
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content2 := []byte("Has A, B, and C")
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, "and-test-2.txt", int64(len(content2)), []string{"tagA", "tagB", "tagC"}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "and-test-2.txt",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{"tagA", "tagB", "tagC"},
|
||||
}
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content3 := []byte("Has only A")
|
||||
_, err = s.Store.CreateFileObject(s.ctx, "and-test-3.txt", int64(len(content3)), []string{"tagA"}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "and-test-3.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{"tagA"},
|
||||
}
|
||||
_, err = s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content4 := []byte("Has only B")
|
||||
_, err = s.Store.CreateFileObject(s.ctx, "and-test-4.txt", int64(len(content4)), []string{"tagB"}, bytes.NewReader(content4))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "and-test-4.txt",
|
||||
Size: int64(len(content4)),
|
||||
Tags: []string{"tagB"},
|
||||
}
|
||||
_, err = s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content4))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Search for files with BOTH tagA AND tagB
|
||||
|
|
@ -546,15 +660,30 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTagsAllTagsRequired() {
|
|||
func (s *FileStoreTestSuite) TestSearchFileObjectByTagsCaseInsensitive() {
|
||||
// Test case insensitivity of tag search (COLLATE NOCASE)
|
||||
content1 := []byte("File with lowercase tag")
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, "case-test-1.txt", int64(len(content1)), []string{"TestTag"}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "case-test-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{"TestTag"},
|
||||
}
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content2 := []byte("File with UPPERCASE tag")
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, "case-test-2.txt", int64(len(content2)), []string{"TESTTAG"}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "case-test-2.txt",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{"TESTTAG"},
|
||||
}
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content3 := []byte("File with MixedCase tag")
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, "case-test-3.txt", int64(len(content3)), []string{"testTAG"}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "case-test-3.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{"testTAG"},
|
||||
}
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Search for lowercase - should return all files (case insensitive)
|
||||
|
|
@ -586,15 +715,30 @@ func (s *FileStoreTestSuite) TestSearchFileObjectByTagsOrderByCreatedAt() {
|
|||
tag := "order-test"
|
||||
|
||||
content1 := []byte("First file")
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, "order-1.txt", int64(len(content1)), []string{tag}, bytes.NewReader(content1))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "order-1.txt",
|
||||
Size: int64(len(content1)),
|
||||
Tags: []string{tag},
|
||||
}
|
||||
file1, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content1))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content2 := []byte("Second file")
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, "order-2.txt", int64(len(content2)), []string{tag}, bytes.NewReader(content2))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "order-2.txt",
|
||||
Size: int64(len(content2)),
|
||||
Tags: []string{tag},
|
||||
}
|
||||
file2, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content2))
|
||||
s.Require().Nil(err)
|
||||
|
||||
content3 := []byte("Third file")
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, "order-3.txt", int64(len(content3)), []string{tag}, bytes.NewReader(content3))
|
||||
param = params.CreateFileObjectParams{
|
||||
Name: "order-3.txt",
|
||||
Size: int64(len(content3)),
|
||||
Tags: []string{tag},
|
||||
}
|
||||
file3, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content3))
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Search and verify order (should be DESC by created_at, so newest first)
|
||||
|
|
@ -629,7 +773,12 @@ func (s *FileStoreTestSuite) TestPaginationFieldsLastPage() {
|
|||
// Create exactly 5 files
|
||||
for i := 0; i < 5; i++ {
|
||||
content := []byte(fmt.Sprintf("Last page test %d", i))
|
||||
_, err := s.Store.CreateFileObject(s.ctx, fmt.Sprintf("last-page-test-%d.txt", i), int64(len(content)), []string{"last-page"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("last-page-test-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"last-page"},
|
||||
}
|
||||
_, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
|
|
@ -649,7 +798,12 @@ func (s *FileStoreTestSuite) TestPaginationFieldsLastPage() {
|
|||
func (s *FileStoreTestSuite) TestPaginationFieldsSinglePage() {
|
||||
// Test when all results fit in a single page
|
||||
content := []byte("Single page test")
|
||||
_, err := s.Store.CreateFileObject(s.ctx, "single-page-test.txt", int64(len(content)), []string{"single-page-unique-tag"}, bytes.NewReader(content))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "single-page-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"single-page-unique-tag"},
|
||||
}
|
||||
_, err := s.Store.CreateFileObject(s.ctx, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
result, err := s.Store.SearchFileObjectByTags(s.ctx, []string{"single-page-unique-tag"}, 1, 20)
|
||||
|
|
|
|||
|
|
@ -51,20 +51,20 @@ type GithubTestSuite struct {
|
|||
db common.Store
|
||||
}
|
||||
|
||||
func (s *GithubTestSuite) TearDownTest() {
|
||||
watcher.CloseWatcher()
|
||||
}
|
||||
|
||||
func (s *GithubTestSuite) SetupTest() {
|
||||
ctx := context.Background()
|
||||
watcher.InitWatcher(ctx)
|
||||
db, err := NewSQLDatabase(context.Background(), garmTesting.GetTestSqliteDBConfig(s.T()))
|
||||
db, err := NewSQLDatabase(ctx, garmTesting.GetTestSqliteDBConfig(s.T()))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
|
||||
}
|
||||
s.db = db
|
||||
}
|
||||
|
||||
func (s *GithubTestSuite) TearDownTest() {
|
||||
watcher.CloseWatcher()
|
||||
}
|
||||
|
||||
func (s *GithubTestSuite) TestDefaultEndpointGetsCreatedAutomaticallyIfNoOtherEndpointExists() {
|
||||
ctx := garmTesting.ImpersonateAdminContext(context.Background(), s.db, s.T())
|
||||
endpoint, err := s.db.GetGithubEndpoint(ctx, defaultGithubEndpoint)
|
||||
|
|
@ -953,9 +953,11 @@ func TestCredentialsAndEndpointMigration(t *testing.T) {
|
|||
// Set the config credentials in the cfg. This is what happens in the main function.
|
||||
// of GARM as well.
|
||||
cfg.MigrateCredentials = credentials
|
||||
|
||||
ctx := context.Background()
|
||||
watcher.InitWatcher(ctx)
|
||||
defer watcher.CloseWatcher()
|
||||
|
||||
db, err := NewSQLDatabase(ctx, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create db connection: %s", err)
|
||||
|
|
|
|||
|
|
@ -79,13 +79,13 @@ func (s *InstancesTestSuite) SetupTest() {
|
|||
ctx := context.Background()
|
||||
watcher.InitWatcher(ctx)
|
||||
// create testing sqlite database
|
||||
db, err := NewSQLDatabase(context.Background(), garmTesting.GetTestSqliteDBConfig(s.T()))
|
||||
db, err := NewSQLDatabase(ctx, garmTesting.GetTestSqliteDBConfig(s.T()))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
|
||||
}
|
||||
s.Store = db
|
||||
|
||||
adminCtx := garmTesting.ImpersonateAdminContext(context.Background(), db, s.T())
|
||||
adminCtx := garmTesting.ImpersonateAdminContext(ctx, db, s.T())
|
||||
s.adminCtx = adminCtx
|
||||
|
||||
githubEndpoint := garmTesting.CreateDefaultGithubEndpoint(adminCtx, db, s.T())
|
||||
|
|
|
|||
|
|
@ -462,7 +462,9 @@ type GiteaCredentials struct {
|
|||
type FileObject struct {
|
||||
gorm.Model
|
||||
// Name is the name of the file
|
||||
Name string `gotm:"type:text,index:idx_fo_name"`
|
||||
Name string `gorm:"type:text;index:idx_fo_name"`
|
||||
// Description is a description for the file
|
||||
Description string `gorm:"type:text"`
|
||||
// FileType holds the MIME type or file type description
|
||||
FileType string `gorm:"type:text"`
|
||||
// Size is the file size in bytes
|
||||
|
|
|
|||
|
|
@ -88,13 +88,13 @@ func (s *OrgTestSuite) SetupTest() {
|
|||
watcher.InitWatcher(ctx)
|
||||
// create testing sqlite database
|
||||
dbConfig := garmTesting.GetTestSqliteDBConfig(s.T())
|
||||
db, err := NewSQLDatabase(context.Background(), dbConfig)
|
||||
db, err := NewSQLDatabase(ctx, dbConfig)
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
|
||||
}
|
||||
s.Store = db
|
||||
|
||||
adminCtx := garmTesting.ImpersonateAdminContext(context.Background(), db, s.T())
|
||||
adminCtx := garmTesting.ImpersonateAdminContext(ctx, db, s.T())
|
||||
s.adminCtx = adminCtx
|
||||
s.adminUserID = auth.UserID(adminCtx)
|
||||
s.Require().NotEmpty(s.adminUserID)
|
||||
|
|
|
|||
|
|
@ -1308,15 +1308,17 @@ type Template struct {
|
|||
// swagger:model Templates
|
||||
type Templates []Template
|
||||
|
||||
// swagger:model FileObject
|
||||
type FileObject struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
Tags []string `json:"tags"`
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
FileType string `json:"file_type"`
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Size int64 `json:"size"`
|
||||
Tags []string `json:"tags"`
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
FileType string `json:"file_type"`
|
||||
}
|
||||
|
||||
type PaginatedResponse[T any] struct {
|
||||
|
|
|
|||
|
|
@ -867,9 +867,11 @@ func (u *UpdateTemplateParams) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// swagger:model UpdateFileObjectParams
|
||||
type UpdateFileObjectParams struct {
|
||||
Name *string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
Name *string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
func (u *UpdateFileObjectParams) Validate() error {
|
||||
|
|
@ -879,3 +881,11 @@ func (u *UpdateFileObjectParams) Validate() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// swagger:model CreateFileObjectParams
|
||||
type CreateFileObjectParams struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Size int64 `json:"size"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
|
|
|||
102
runner/object_store.go
Normal file
102
runner/object_store.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2025 Cloudbase Solutions 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.
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
|
||||
"github.com/cloudbase/garm/auth"
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
func (r *Runner) CreateFileObject(ctx context.Context, param params.CreateFileObjectParams, reader io.Reader) (params.FileObject, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.FileObject{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
fileObj, err := r.store.CreateFileObject(ctx, param, reader)
|
||||
if err != nil {
|
||||
return params.FileObject{}, fmt.Errorf("failed to create file object: %w", err)
|
||||
}
|
||||
return fileObj, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetFileObject(ctx context.Context, objID uint) (params.FileObject, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.FileObject{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
fileObj, err := r.store.GetFileObject(ctx, objID)
|
||||
if err != nil {
|
||||
return params.FileObject{}, fmt.Errorf("failed to get file object: %w", err)
|
||||
}
|
||||
|
||||
return fileObj, nil
|
||||
}
|
||||
|
||||
func (r *Runner) DeleteFileObject(ctx context.Context, objID uint) error {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
if err := r.store.DeleteFileObject(ctx, objID); err != nil {
|
||||
return fmt.Errorf("failed to delete file object: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) ListFileObjects(ctx context.Context, page, pageSize uint64, tags []string) (params.FileObjectPaginatedResponse, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.FileObjectPaginatedResponse{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
var resp params.FileObjectPaginatedResponse
|
||||
var err error
|
||||
if len(tags) == 0 {
|
||||
resp, err = r.store.ListFileObjects(ctx, page, pageSize)
|
||||
} else {
|
||||
resp, err = r.store.SearchFileObjectByTags(ctx, tags, page, pageSize)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return params.FileObjectPaginatedResponse{}, fmt.Errorf("failed to list objects: %w", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (r *Runner) UpdateFileObject(ctx context.Context, objID uint, param params.UpdateFileObjectParams) (params.FileObject, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return params.FileObject{}, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
resp, err := r.store.UpdateFileObject(ctx, objID, param)
|
||||
if err != nil {
|
||||
return params.FileObject{}, fmt.Errorf("failed to update object: %w", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (r *Runner) GetFileObjectReader(ctx context.Context, objID uint) (io.ReadCloser, error) {
|
||||
if !auth.IsAdmin(ctx) {
|
||||
return nil, runnerErrors.ErrUnauthorized
|
||||
}
|
||||
|
||||
readCloser, err := r.store.OpenFileObjectContent(ctx, objID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file object: %w", err)
|
||||
}
|
||||
return readCloser, nil
|
||||
}
|
||||
353
runner/object_store_test.go
Normal file
353
runner/object_store_test.go
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
// Copyright 2025 Cloudbase Solutions 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.
|
||||
|
||||
//go:build testing
|
||||
// +build testing
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
runnerErrors "github.com/cloudbase/garm-provider-common/errors"
|
||||
"github.com/cloudbase/garm/database"
|
||||
dbCommon "github.com/cloudbase/garm/database/common"
|
||||
garmTesting "github.com/cloudbase/garm/internal/testing"
|
||||
"github.com/cloudbase/garm/params"
|
||||
)
|
||||
|
||||
type ObjectStoreTestFixtures struct {
|
||||
AdminContext context.Context
|
||||
UnauthorizedContext context.Context
|
||||
Store dbCommon.Store
|
||||
CreateObjectParams params.CreateFileObjectParams
|
||||
UpdateObjectParams params.UpdateFileObjectParams
|
||||
TestFileObject params.FileObject
|
||||
TestFileContent []byte
|
||||
}
|
||||
|
||||
type ObjectStoreTestSuite struct {
|
||||
suite.Suite
|
||||
Fixtures *ObjectStoreTestFixtures
|
||||
Runner *Runner
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) SetupTest() {
|
||||
// create testing sqlite database
|
||||
dbCfg := garmTesting.GetTestSqliteDBConfig(s.T())
|
||||
db, err := database.NewDatabase(context.Background(), dbCfg)
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create db connection: %s", err))
|
||||
}
|
||||
|
||||
adminCtx := garmTesting.ImpersonateAdminContext(context.Background(), db, s.T())
|
||||
|
||||
// Create a test file object
|
||||
testContent := []byte("test file content for object store")
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "test-file.bin",
|
||||
Size: int64(len(testContent)),
|
||||
Tags: []string{"test", "binary"},
|
||||
}
|
||||
fileObj, err := db.CreateFileObject(adminCtx, param, bytes.NewReader(testContent))
|
||||
if err != nil {
|
||||
s.FailNow(fmt.Sprintf("failed to create test file object: %s", err))
|
||||
}
|
||||
|
||||
updatedName := "updated-file.txt"
|
||||
// Setup fixtures
|
||||
fixtures := &ObjectStoreTestFixtures{
|
||||
AdminContext: adminCtx,
|
||||
UnauthorizedContext: context.Background(),
|
||||
Store: db,
|
||||
CreateObjectParams: params.CreateFileObjectParams{
|
||||
Name: "new-file.txt",
|
||||
Size: 100,
|
||||
Tags: []string{"new", "test"},
|
||||
},
|
||||
UpdateObjectParams: params.UpdateFileObjectParams{
|
||||
Name: &updatedName,
|
||||
Tags: []string{"updated", "test"},
|
||||
},
|
||||
TestFileObject: fileObj,
|
||||
TestFileContent: testContent,
|
||||
}
|
||||
s.Fixtures = fixtures
|
||||
|
||||
// Setup test runner
|
||||
runner := &Runner{
|
||||
ctx: fixtures.AdminContext,
|
||||
store: fixtures.Store,
|
||||
}
|
||||
s.Runner = runner
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestCreateFileObject() {
|
||||
content := []byte("new file content")
|
||||
reader := bytes.NewReader(content)
|
||||
|
||||
createParams := params.CreateFileObjectParams{
|
||||
Name: "create-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"create", "test"},
|
||||
}
|
||||
|
||||
fileObj, err := s.Runner.CreateFileObject(s.Fixtures.AdminContext, createParams, reader)
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotEmpty(fileObj.ID)
|
||||
s.Require().Equal(createParams.Name, fileObj.Name)
|
||||
s.Require().Equal(createParams.Size, fileObj.Size)
|
||||
s.Require().ElementsMatch(createParams.Tags, fileObj.Tags)
|
||||
s.Require().NotEmpty(fileObj.SHA256)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestCreateFileObjectUnauthorized() {
|
||||
content := []byte("unauthorized content")
|
||||
reader := bytes.NewReader(content)
|
||||
|
||||
_, err := s.Runner.CreateFileObject(s.Fixtures.UnauthorizedContext, s.Fixtures.CreateObjectParams, reader)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObject() {
|
||||
fileObj, err := s.Runner.GetFileObject(s.Fixtures.AdminContext, s.Fixtures.TestFileObject.ID)
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().Equal(s.Fixtures.TestFileObject.ID, fileObj.ID)
|
||||
s.Require().Equal(s.Fixtures.TestFileObject.Name, fileObj.Name)
|
||||
s.Require().Equal(s.Fixtures.TestFileObject.Size, fileObj.Size)
|
||||
s.Require().ElementsMatch(s.Fixtures.TestFileObject.Tags, fileObj.Tags)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObjectUnauthorized() {
|
||||
_, err := s.Runner.GetFileObject(s.Fixtures.UnauthorizedContext, s.Fixtures.TestFileObject.ID)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObjectNotFound() {
|
||||
_, err := s.Runner.GetFileObject(s.Fixtures.AdminContext, 99999)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().Contains(err.Error(), "failed to get file object")
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestDeleteFileObject() {
|
||||
// Create a file to delete
|
||||
content := []byte("file to delete")
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "delete-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"delete"},
|
||||
}
|
||||
fileObj, err := s.Fixtures.Store.CreateFileObject(s.Fixtures.AdminContext, param, bytes.NewReader(content))
|
||||
s.Require().Nil(err)
|
||||
|
||||
err = s.Runner.DeleteFileObject(s.Fixtures.AdminContext, fileObj.ID)
|
||||
|
||||
s.Require().Nil(err)
|
||||
|
||||
// Verify it's deleted
|
||||
_, err = s.Fixtures.Store.GetFileObject(s.Fixtures.AdminContext, fileObj.ID)
|
||||
s.Require().NotNil(err)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestDeleteFileObjectUnauthorized() {
|
||||
err := s.Runner.DeleteFileObject(s.Fixtures.UnauthorizedContext, s.Fixtures.TestFileObject.ID)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestDeleteFileObjectNotFound() {
|
||||
// Delete of non-existent object is a noop and returns nil (idempotent)
|
||||
err := s.Runner.DeleteFileObject(s.Fixtures.AdminContext, 99999)
|
||||
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestListFileObjects() {
|
||||
// Create additional test files
|
||||
for i := 1; i <= 3; i++ {
|
||||
content := []byte(fmt.Sprintf("test file %d", i))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("list-test-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"list", "test"},
|
||||
}
|
||||
_, err := s.Fixtures.Store.CreateFileObject(
|
||||
s.Fixtures.AdminContext,
|
||||
param,
|
||||
bytes.NewReader(content),
|
||||
)
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
resp, err := s.Runner.ListFileObjects(s.Fixtures.AdminContext, 0, 25, nil)
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotNil(resp.Results)
|
||||
s.Require().GreaterOrEqual(len(resp.Results), 4) // At least the test file + 3 new ones
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestListFileObjectsUnauthorized() {
|
||||
_, err := s.Runner.ListFileObjects(s.Fixtures.UnauthorizedContext, 0, 25, nil)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestListFileObjectsWithTags() {
|
||||
// Create files with specific tags
|
||||
specificTag := "specific-list-tag"
|
||||
for i := 1; i <= 2; i++ {
|
||||
content := []byte(fmt.Sprintf("tagged file %d", i))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("tagged-list-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{specificTag, "test"},
|
||||
}
|
||||
_, err := s.Fixtures.Store.CreateFileObject(
|
||||
s.Fixtures.AdminContext,
|
||||
param,
|
||||
bytes.NewReader(content),
|
||||
)
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
resp, err := s.Runner.ListFileObjects(s.Fixtures.AdminContext, 0, 25, []string{specificTag})
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotNil(resp.Results)
|
||||
s.Require().GreaterOrEqual(len(resp.Results), 2)
|
||||
// Verify all results have the specific tag
|
||||
for _, obj := range resp.Results {
|
||||
s.Require().Contains(obj.Tags, specificTag)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestListFileObjectsPagination() {
|
||||
// Create multiple files for pagination test
|
||||
for i := 1; i <= 10; i++ {
|
||||
content := []byte(fmt.Sprintf("pagination file %d", i))
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: fmt.Sprintf("page-test-%d.txt", i),
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"pagination"},
|
||||
}
|
||||
_, err := s.Fixtures.Store.CreateFileObject(
|
||||
s.Fixtures.AdminContext,
|
||||
param,
|
||||
bytes.NewReader(content),
|
||||
)
|
||||
s.Require().Nil(err)
|
||||
}
|
||||
|
||||
// Get first page
|
||||
resp1, err := s.Runner.ListFileObjects(s.Fixtures.AdminContext, 1, 5, []string{"pagination"})
|
||||
s.Require().Nil(err)
|
||||
s.Require().Len(resp1.Results, 5)
|
||||
|
||||
// Get second page
|
||||
resp2, err := s.Runner.ListFileObjects(s.Fixtures.AdminContext, 2, 5, []string{"pagination"})
|
||||
s.Require().Nil(err)
|
||||
s.Require().Len(resp2.Results, 5)
|
||||
|
||||
// Verify different results on different pages
|
||||
s.Require().NotEqual(resp1.Results[0].ID, resp2.Results[0].ID)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestUpdateFileObject() {
|
||||
// Create a file to update
|
||||
content := []byte("original content")
|
||||
param := params.CreateFileObjectParams{
|
||||
Name: "update-test.txt",
|
||||
Size: int64(len(content)),
|
||||
Tags: []string{"original"},
|
||||
}
|
||||
fileObj, err := s.Fixtures.Store.CreateFileObject(
|
||||
s.Fixtures.AdminContext,
|
||||
param,
|
||||
bytes.NewReader(content),
|
||||
)
|
||||
s.Require().Nil(err)
|
||||
|
||||
newName := "updated-name.txt"
|
||||
updateParams := params.UpdateFileObjectParams{
|
||||
Name: &newName,
|
||||
Tags: []string{"updated", "modified"},
|
||||
}
|
||||
|
||||
updatedObj, err := s.Runner.UpdateFileObject(s.Fixtures.AdminContext, fileObj.ID, updateParams)
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().Equal(*updateParams.Name, updatedObj.Name)
|
||||
s.Require().ElementsMatch(updateParams.Tags, updatedObj.Tags)
|
||||
s.Require().Equal(fileObj.ID, updatedObj.ID)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestUpdateFileObjectUnauthorized() {
|
||||
_, err := s.Runner.UpdateFileObject(s.Fixtures.UnauthorizedContext, s.Fixtures.TestFileObject.ID, s.Fixtures.UpdateObjectParams)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestUpdateFileObjectNotFound() {
|
||||
_, err := s.Runner.UpdateFileObject(s.Fixtures.AdminContext, 99999, s.Fixtures.UpdateObjectParams)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().Contains(err.Error(), "failed to update object")
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObjectReader() {
|
||||
reader, err := s.Runner.GetFileObjectReader(s.Fixtures.AdminContext, s.Fixtures.TestFileObject.ID)
|
||||
|
||||
s.Require().Nil(err)
|
||||
s.Require().NotNil(reader)
|
||||
defer reader.Close()
|
||||
|
||||
// Read the content
|
||||
content, err := io.ReadAll(reader)
|
||||
s.Require().Nil(err)
|
||||
s.Require().Equal(s.Fixtures.TestFileContent, content)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObjectReaderUnauthorized() {
|
||||
_, err := s.Runner.GetFileObjectReader(s.Fixtures.UnauthorizedContext, s.Fixtures.TestFileObject.ID)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().ErrorIs(err, runnerErrors.ErrUnauthorized)
|
||||
}
|
||||
|
||||
func (s *ObjectStoreTestSuite) TestGetFileObjectReaderNotFound() {
|
||||
_, err := s.Runner.GetFileObjectReader(s.Fixtures.AdminContext, 99999)
|
||||
|
||||
s.Require().NotNil(err)
|
||||
s.Require().Contains(err.Error(), "failed to open file object")
|
||||
}
|
||||
|
||||
func TestObjectStoreTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(ObjectStoreTestSuite))
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/assets/0.BSyLSYks.css
Normal file
1
webapp/assets/_app/immutable/assets/0.BSyLSYks.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/assets/_layout.BSyLSYks.css
Normal file
1
webapp/assets/_app/immutable/assets/_layout.BSyLSYks.css
Normal file
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/30NlHgQ_.js
Normal file
1
webapp/assets/_app/immutable/chunks/30NlHgQ_.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as H}from"./TJn6xDN9.js";import{p as J,l as j,h as K,f as g,t as h,b as k,c as L,s as u,d as r,k as z,m as E,r as a,q as l,u as p,g as _,e as y}from"./DniTuB_0.js";import{p as d,i as I}from"./DbNhg6mG.js";import{c as M,s as P,d as n}from"./DSfKzFV1.js";var Q=g('<div class="group relative flex-shrink-0"><svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> <div class="absolute left-0 top-full mt-1 z-10 invisible group-hover:visible opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none w-64"><div class="bg-gray-900 dark:bg-gray-700 text-white text-xs rounded-md px-3 py-2 shadow-lg"><div class="font-semibold mb-1">Description:</div> <div class="whitespace-pre-wrap break-words max-h-32 overflow-y-auto"> </div></div></div></div>'),S=g('<div class="text-sm text-gray-500 dark:text-gray-400 truncate"> </div>'),V=g('<div class="w-full min-w-0 text-sm font-medium"><div class="flex items-center gap-1.5"><a> </a> <!></div> <!></div>');function te(C,i){J(i,!1);const m=E(),b=E();let e=d(i,"item",8),s=d(i,"entityType",8,"repository"),N=d(i,"showOwner",8,!1),O=d(i,"showId",8,!1),T=d(i,"fontMono",8,!1);function q(){if(!e())return"Unknown";switch(s()){case"repository":return N()?`${e().owner||"Unknown"}/${e().name||"Unknown"}`:e().name||"Unknown";case"organization":case"enterprise":return e().name||"Unknown";case"pool":return O()?e().id||"Unknown":e().name||"Unknown";case"scaleset":return e().name||"Unknown";case"instance":return e().name||"Unknown";case"template":return e().name||"Unknown";case"object":return e().name||"Unknown";default:return e().name||e().id||"Unknown"}}function B(){if(!e())return"#";let t;switch(s()){case"instance":t=e().name;break;default:t=e().id||e().name;break}if(!t)return"#";switch(s()){case"repository":return n(`/repositories/${t}`);case"organization":return n(`/organizations/${t}`);case"enterprise":return n(`/enterprises/${t}`);case"pool":return n(`/pools/${t}`);case"scaleset":return n(`/scalesets/${t}`);case"instance":return n(`/instances/${encodeURIComponent(t)}`);case"template":return n(`/templates/${t}`);case"object":return n(`/objects/${t}`);default:return"#"}}j(()=>{},()=>{z(m,q())}),j(()=>{},()=>{z(b,B())}),K(),H();var f=V(),w=r(f),c=r(w),D=r(c,!0);a(c);var R=u(c,2);{var $=t=>{var o=Q(),v=u(r(o),2),x=r(v),U=u(r(x),2),G=r(U,!0);a(U),a(x),a(v),a(o),h(()=>y(G,(l(e()),p(()=>e().description)))),k(t,o)};I(R,t=>{l(s()),l(e()),p(()=>s()==="object"&&e()?.description)&&t($)})}a(w);var A=u(w,2);{var F=t=>{var o=S(),v=r(o,!0);a(o),h(()=>y(v,(l(e()),p(()=>e().provider_id)))),k(t,o)};I(A,t=>{l(s()),l(e()),p(()=>s()==="instance"&&e()?.provider_id)&&t(F)})}a(f),h(()=>{M(c,"href",_(b)),P(c,1,`truncate text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 ${T()?"font-mono":""}`),M(c,"title",_(m)),y(D,_(m))}),k(C,f),L()}export{te as E};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as D}from"./TJn6xDN9.js";import{p as P,f as I,d as s,r as n,s as u,u as l,q as i,t as w,e as S,b as N,c as A}from"./DniTuB_0.js";import{d as f,c as F}from"./BZ2rxtTc.js";import{p as d}from"./DbNhg6mG.js";import{D as E,G,A as j}from"./CKaB5fL4.js";import{E as q}from"./Dh8uHEF5.js";import{S as g}from"./C1GM4Goa.js";var L=I('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="flex items-center justify-between mb-4"><h2 class="text-lg font-medium text-gray-900 dark:text-white"> </h2> <a class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">View all instances</a></div> <!></div></div>');function O(y,a){P(a,!1);let e=d(a,"instances",8),h=d(a,"entityType",8),v=d(a,"onDeleteInstance",8);const b=[{key:"name",title:"Name",cellComponent:q,cellProps:{entityType:"instance",nameField:"name"}},{key:"status",title:"Status",cellComponent:g,cellProps:{statusType:"instance",statusField:"status"}},{key:"runner_status",title:"Runner Status",cellComponent:g,cellProps:{statusType:"instance",statusField:"runner_status"}},{key:"created",title:"Created",cellComponent:G,cellProps:{field:"created_at",type:"date"}},{key:"actions",title:"Actions",align:"right",cellComponent:j,cellProps:{actions:[{type:"delete",label:"Delete",title:"Delete instance",ariaLabel:"Delete instance",action:"delete"}]}}],x={entityType:"instance",primaryText:{field:"name",isClickable:!0,href:"/instances/{name}"},secondaryText:{field:"provider_id"},badges:[{type:"status",field:"status"}],actions:[{type:"delete",handler:t=>m(t)}]};function m(t){v()(t)}function C(t){m(t.detail.item)}D();var r=L(),p=s(r),o=s(p),c=s(o),T=s(c);n(c);var _=u(c,2);n(o);var k=u(o,2);E(k,{get columns(){return b},get data(){return e()},loading:!1,error:"",searchTerm:"",showSearch:!1,showPagination:!1,currentPage:1,get perPage(){return i(e()),l(()=>e().length)},totalPages:1,get totalItems(){return i(e()),l(()=>e().length)},itemName:"instances",emptyTitle:"No instances running",get emptyMessage(){return`No instances running for this ${h()??""}.`},emptyIconType:"cog",get mobileCardConfig(){return x},$$events:{delete:C}}),n(p),n(r),w(t=>{S(T,`Instances (${i(e()),l(()=>e().length)??""})`),F(_,"href",t)},[()=>(i(f),l(()=>f("/instances")))]),N(y,r),A()}export{O as I};
|
||||
import"./DsnmJJEf.js";import{i as D}from"./TJn6xDN9.js";import{p as P,f as I,d as s,r as n,s as u,u as l,q as i,t as w,e as S,b as N,c as A}from"./DniTuB_0.js";import{d as f,c as F}from"./DSfKzFV1.js";import{p as d}from"./DbNhg6mG.js";import{D as E,G,A as j}from"./BlJ06z1t.js";import{E as q}from"./30NlHgQ_.js";import{S as g}from"./BsX_CrDw.js";var L=I('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="flex items-center justify-between mb-4"><h2 class="text-lg font-medium text-gray-900 dark:text-white"> </h2> <a class="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">View all instances</a></div> <!></div></div>');function O(y,a){P(a,!1);let e=d(a,"instances",8),h=d(a,"entityType",8),v=d(a,"onDeleteInstance",8);const b=[{key:"name",title:"Name",cellComponent:q,cellProps:{entityType:"instance",nameField:"name"}},{key:"status",title:"Status",cellComponent:g,cellProps:{statusType:"instance",statusField:"status"}},{key:"runner_status",title:"Runner Status",cellComponent:g,cellProps:{statusType:"instance",statusField:"runner_status"}},{key:"created",title:"Created",cellComponent:G,cellProps:{field:"created_at",type:"date"}},{key:"actions",title:"Actions",align:"right",cellComponent:j,cellProps:{actions:[{type:"delete",label:"Delete",title:"Delete instance",ariaLabel:"Delete instance",action:"delete"}]}}],x={entityType:"instance",primaryText:{field:"name",isClickable:!0,href:"/instances/{name}"},secondaryText:{field:"provider_id"},badges:[{type:"status",field:"status"}],actions:[{type:"delete",handler:t=>m(t)}]};function m(t){v()(t)}function C(t){m(t.detail.item)}D();var r=L(),p=s(r),o=s(p),c=s(o),T=s(c);n(c);var _=u(c,2);n(o);var k=u(o,2);E(k,{get columns(){return b},get data(){return e()},loading:!1,error:"",searchTerm:"",showSearch:!1,showPagination:!1,currentPage:1,get perPage(){return i(e()),l(()=>e().length)},totalPages:1,get totalItems(){return i(e()),l(()=>e().length)},itemName:"instances",emptyTitle:"No instances running",get emptyMessage(){return`No instances running for this ${h()??""}.`},emptyIconType:"cog",get mobileCardConfig(){return x},$$events:{delete:C}}),n(p),n(r),w(t=>{S(T,`Instances (${i(e()),l(()=>e().length)??""})`),F(_,"href",t)},[()=>(i(f),l(()=>f("/instances")))]),N(y,r),A()}export{O as I};
|
||||
4
webapp/assets/_app/immutable/chunks/BC4TpgBU.js
Normal file
4
webapp/assets/_app/immutable/chunks/BC4TpgBU.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import{d as o}from"./DSfKzFV1.js";function l(r){if(!r)return"N/A";try{return(typeof r=="string"?new Date(r):r).toLocaleString()}catch{return"Invalid Date"}}function f(r,e="w-4 h-4"){return r==="gitea"?`<svg class="${e}" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 640 640"><path d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12" style="fill:#fff"/><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6M125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1m300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1" style="fill:#609926"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8s2 16.3 9.1 20c7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3s17.4 1.7 22.5-5.3c5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8z" style="fill:#609926"/></svg>`:r==="github"?`<div class="inline-flex ${e}"><svg class="${e} dark:hidden" width="98" height="96" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg><svg class="${e} hidden dark:block" width="98" height="96" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg></div>`:`<svg class="${e} text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>`}function d(r,e){if(r.repo_name)return r.repo_name;if(r.org_name)return r.org_name;if(r.enterprise_name)return r.enterprise_name;if(r.repo_id&&!r.repo_name&&e?.repositories){const n=e.repositories.find(t=>t.id===r.repo_id);return n?`${n.owner}/${n.name}`:"Unknown Entity"}if(r.org_id&&!r.org_name&&e?.organizations){const n=e.organizations.find(t=>t.id===r.org_id);return n&&n.name?n.name:"Unknown Entity"}if(r.enterprise_id&&!r.enterprise_name&&e?.enterprises){const n=e.enterprises.find(t=>t.id===r.enterprise_id);return n&&n.name?n.name:"Unknown Entity"}return"Unknown Entity"}function p(r){return r.repo_id?"repository":r.org_id?"organization":r.enterprise_id?"enterprise":"unknown"}function g(r){return r.repo_id?o(`/repositories/${r.repo_id}`):r.org_id?o(`/organizations/${r.org_id}`):r.enterprise_id?o(`/enterprises/${r.enterprise_id}`):"#"}function w(r){r&&(r.scrollTop=r.scrollHeight)}function m(r){return{newPerPage:r,newCurrentPage:1}}function v(r){return r.pool_manager_status?.running?{text:"Running",variant:"success"}:{text:"Stopped",variant:"error"}}function _(r){switch(r.toLowerCase()){case"error":return{text:"Error",variant:"error"};case"warning":return{text:"Warning",variant:"warning"};case"info":return{text:"Info",variant:"info"};default:return{text:r,variant:"info"}}}function i(r,e,n){if(!e.trim())return r;const t=e.toLowerCase();return r.filter(s=>typeof n=="function"?n(s).toLowerCase().includes(t):n.some(a=>s[a]?.toString().toLowerCase().includes(t)))}function h(r,e){return i(r,e,["name","owner"])}function x(r,e){return i(r,e,["name"])}function k(r,e){return i(r,e,n=>[n.name||"",n.description||"",n.endpoint?.name||""].join(" "))}function E(r,e){return i(r,e,["name","description","base_url","api_base_url"])}function L(r,e,n){return r.slice((e-1)*n,e*n)}export{E as a,l as b,m as c,_ as d,d as e,k as f,f as g,i as h,p as i,g as j,v as k,x as l,h as m,L as p,w as s};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/BehbwORU.js
Normal file
1
webapp/assets/_app/immutable/chunks/BehbwORU.js
Normal file
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/BlJ06z1t.js
Normal file
1
webapp/assets/_app/immutable/chunks/BlJ06z1t.js
Normal file
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/BsX_CrDw.js
Normal file
1
webapp/assets/_app/immutable/chunks/BsX_CrDw.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as v}from"./TJn6xDN9.js";import{p as w,l as m,q as s,g as r,m as g,h as x,A as h,a as T,b as S,c as A,k,u}from"./DniTuB_0.js";import{k as B}from"./BlJ06z1t.js";import{p}from"./DbNhg6mG.js";import{B as C}from"./Dyp1NLoF.js";import{k as b}from"./BC4TpgBU.js";import{f as E}from"./ow_oMtSd.js";function z(_,i){w(i,!1);const c=g(),n=g();let e=p(i,"item",8),d=p(i,"statusType",8,"entity"),a=p(i,"statusField",8,"status");m(()=>(s(e()),s(a())),()=>{k(c,e()?.[a()]||"unknown")}),m(()=>(s(e()),s(d()),r(c),s(a())),()=>{k(n,(()=>{if(!e())return{variant:"error",text:"Unknown"};switch(d()){case"entity":return b(e());case"instance":let t="secondary";switch(r(c).toLowerCase()){case"running":t="success";break;case"stopped":t="info";break;case"creating":case"pending_create":t="warning";break;case"deleting":case"pending_delete":case"pending_force_delete":t="warning";break;case"error":case"deleted":t="error";break;case"active":case"online":t="success";break;case"idle":t="info";break;case"pending":case"installing":t="warning";break;case"failed":case"terminated":case"offline":t="error";break;case"unknown":default:t="secondary";break}return{variant:t,text:E(r(c))};case"enabled":return{variant:e().enabled?"success":"error",text:e().enabled?"Enabled":"Disabled"};case"custom":const o=e()[a()]||"Unknown";if(a()==="auth-type"){const f=o==="pat"||!o?"pat":"app";return{variant:f==="pat"?"success":"info",text:f==="pat"?"PAT":"App"}}return{variant:"info",text:o};default:return b(e())}})())}),x(),v();var l=h(),y=T(l);B(y,()=>(s(e()),s(a()),u(()=>`${e()?.name||"item"}-${e()?.[a()]||"status"}-${e()?.updated_at||"time"}`)),t=>{C(t,{get variant(){return r(n),u(()=>r(n).variant)},get text(){return r(n),u(()=>r(n).text)}})}),S(_,l),A()}export{z as S};
|
||||
|
|
@ -1 +0,0 @@
|
|||
import"./DsnmJJEf.js";import{i as v}from"./TJn6xDN9.js";import{p as w,l as m,q as s,g as r,m as g,h as x,A as h,a as T,b as S,c as A,k,u}from"./DniTuB_0.js";import{k as B}from"./CKaB5fL4.js";import{p as d}from"./DbNhg6mG.js";import{k as b,B as C}from"./CTcPpzia.js";import{f as E}from"./ow_oMtSd.js";function j(_,i){w(i,!1);const c=g(),n=g();let e=d(i,"item",8),l=d(i,"statusType",8,"entity"),a=d(i,"statusField",8,"status");m(()=>(s(e()),s(a())),()=>{k(c,e()?.[a()]||"unknown")}),m(()=>(s(e()),s(l()),r(c),s(a())),()=>{k(n,(()=>{if(!e())return{variant:"error",text:"Unknown"};switch(l()){case"entity":return b(e());case"instance":let t="secondary";switch(r(c).toLowerCase()){case"running":t="success";break;case"stopped":t="info";break;case"creating":case"pending_create":t="warning";break;case"deleting":case"pending_delete":case"pending_force_delete":t="warning";break;case"error":case"deleted":t="error";break;case"active":case"online":t="success";break;case"idle":t="info";break;case"pending":case"installing":t="warning";break;case"failed":case"terminated":case"offline":t="error";break;case"unknown":default:t="secondary";break}return{variant:t,text:E(r(c))};case"enabled":return{variant:e().enabled?"success":"error",text:e().enabled?"Enabled":"Disabled"};case"custom":const o=e()[a()]||"Unknown";if(a()==="auth-type"){const f=o==="pat"||!o?"pat":"app";return{variant:f==="pat"?"success":"info",text:f==="pat"?"PAT":"App"}}return{variant:"info",text:o};default:return b(e())}})())}),x(),v();var p=h(),y=T(p);B(y,()=>(s(e()),s(a()),u(()=>`${e()?.name||"item"}-${e()?.[a()]||"status"}-${e()?.updated_at||"time"}`)),t=>{C(t,{get variant(){return r(n),u(()=>r(n).variant)},get text(){return r(n),u(()=>r(n).text)}})}),S(_,p),A()}export{j as S};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as _}from"./TJn6xDN9.js";import{p as h,f as x,t as u,b as g,c as k,s as w,d as o,u as d,q as e,r,e as y}from"./DniTuB_0.js";import{h as b}from"./BZ2rxtTc.js";import{p as m}from"./DbNhg6mG.js";import{g as l}from"./CTcPpzia.js";var z=x('<div class="flex items-center"><div class="flex-shrink-0 mr-2"><!></div> <div class="text-sm text-gray-900 dark:text-white"> </div></div>');function U(v,i){h(i,!1);let t=m(i,"item",8),s=m(i,"iconSize",8,"w-5 h-5");_();var a=z(),n=o(a),f=o(n);b(f,()=>(e(l),e(t()),e(s()),d(()=>l(t()?.endpoint?.endpoint_type||t()?.endpoint_type||"unknown",s())))),r(n);var p=w(n,2),c=o(p,!0);r(p),r(a),u(()=>y(c,(e(t()),d(()=>t()?.endpoint?.name||t()?.endpoint_name||t()?.endpoint_type||"Unknown")))),g(v,a),k()}export{U as E};
|
||||
import"./DsnmJJEf.js";import{i as _}from"./TJn6xDN9.js";import{p as h,f as x,t as u,b as g,c as k,s as w,d as o,u as d,q as e,r,e as y}from"./DniTuB_0.js";import{h as b}from"./DSfKzFV1.js";import{p as m}from"./DbNhg6mG.js";import{g as l}from"./BC4TpgBU.js";var z=x('<div class="flex items-center"><div class="flex-shrink-0 mr-2"><!></div> <div class="text-sm text-gray-900 dark:text-white"> </div></div>');function U(v,i){h(i,!1);let t=m(i,"item",8),s=m(i,"iconSize",8,"w-5 h-5");_();var a=z(),n=o(a),f=o(n);b(f,()=>(e(l),e(t()),e(s()),d(()=>l(t()?.endpoint?.endpoint_type||t()?.endpoint_type||"unknown",s())))),r(n);var p=w(n,2),c=o(p,!0);r(p),r(a),u(()=>y(c,(e(t()),d(()=>t()?.endpoint?.name||t()?.endpoint_name||t()?.endpoint_type||"Unknown")))),g(v,a),k()}export{U as E};
|
||||
|
|
@ -1 +0,0 @@
|
|||
import"./DsnmJJEf.js";import{i as u}from"./TJn6xDN9.js";import{p as v,E as m,f as h,d as r,r as d,i,b as k,c as g}from"./DniTuB_0.js";import{i as b}from"./BZ2rxtTc.js";var w=h('<div class="fixed inset-0 bg-black/30 dark:bg-black/50 overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4" role="dialog" aria-modal="true" tabindex="-1"><div class="relative mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-lg" role="document"><!></div></div>');function M(s,t){v(t,!1);const l=m();function n(){l("close")}function c(o){o.stopPropagation()}function f(o){o.key==="Escape"&&l("close")}u();var a=w(),e=r(a),p=r(e);b(p,t,"default",{}),d(e),d(a),i("click",e,c),i("click",a,n),i("keydown",a,f),k(s,a),g()}export{M};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as j}from"./TJn6xDN9.js";import{p as E,E as G,f as S,d as t,r,s as g,u,q as p,z as m,t as q,e as z,i as f,b as D,c as H}from"./DniTuB_0.js";import{h as y,s as h}from"./BZ2rxtTc.js";import{p as v}from"./DbNhg6mG.js";import{g as o}from"./CTcPpzia.js";var I=S('<fieldset><legend class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> </legend> <div class="grid grid-cols-2 gap-4"><button type="button"><!> <span class="mt-2 text-sm font-medium text-gray-900 dark:text-white">GitHub</span></button> <button type="button"><!> <span class="mt-2 text-sm font-medium text-gray-900 dark:text-white">Gitea</span></button></div></fieldset>');function M(x,s){E(s,!1);const k=G();let i=v(s,"selectedForgeType",12,""),_=v(s,"label",8,"Select Forge Type");function n(c){i(c),k("select",c)}j();var d=I(),l=t(d),F=t(l,!0);r(l);var b=g(l,2),e=t(b),w=t(e);y(w,()=>(p(o),u(()=>o("github","w-8 h-8")))),m(2),r(e);var a=g(e,2),T=t(a);y(T,()=>(p(o),u(()=>o("gitea","w-8 h-8")))),m(2),r(a),r(b),r(d),q(()=>{z(F,_()),h(e,1,`flex flex-col items-center justify-center p-6 border-2 rounded-lg transition-colors cursor-pointer ${i()==="github"?"border-blue-500 bg-blue-50 dark:bg-blue-900":"border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"}`),h(a,1,`flex flex-col items-center justify-center p-6 border-2 rounded-lg transition-colors cursor-pointer ${i()==="gitea"?"border-blue-500 bg-blue-50 dark:bg-blue-900":"border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"}`)}),f("click",e,()=>n("github")),f("click",a,()=>n("gitea")),D(x,d),H()}export{M as F};
|
||||
import"./DsnmJJEf.js";import{i as j}from"./TJn6xDN9.js";import{p as E,E as G,f as S,d as t,r,s as g,u,q as p,z as m,t as q,e as z,i as f,b as D,c as H}from"./DniTuB_0.js";import{h as y,s as h}from"./DSfKzFV1.js";import{p as v}from"./DbNhg6mG.js";import{g as o}from"./BC4TpgBU.js";var I=S('<fieldset><legend class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> </legend> <div class="grid grid-cols-2 gap-4"><button type="button"><!> <span class="mt-2 text-sm font-medium text-gray-900 dark:text-white">GitHub</span></button> <button type="button"><!> <span class="mt-2 text-sm font-medium text-gray-900 dark:text-white">Gitea</span></button></div></fieldset>');function M(x,s){E(s,!1);const k=G();let i=v(s,"selectedForgeType",12,""),_=v(s,"label",8,"Select Forge Type");function n(c){i(c),k("select",c)}j();var d=I(),l=t(d),F=t(l,!0);r(l);var b=g(l,2),e=t(b),w=t(e);y(w,()=>(p(o),u(()=>o("github","w-8 h-8")))),m(2),r(e);var a=g(e,2),T=t(a);y(T,()=>(p(o),u(()=>o("gitea","w-8 h-8")))),m(2),r(a),r(b),r(d),q(()=>{z(F,_()),h(e,1,`flex flex-col items-center justify-center p-6 border-2 rounded-lg transition-colors cursor-pointer ${i()==="github"?"border-blue-500 bg-blue-50 dark:bg-blue-900":"border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"}`),h(a,1,`flex flex-col items-center justify-center p-6 border-2 rounded-lg transition-colors cursor-pointer ${i()==="gitea"?"border-blue-500 bg-blue-50 dark:bg-blue-900":"border-gray-300 dark:border-gray-600 hover:border-gray-400 dark:hover:border-gray-500"}`)}),f("click",e,()=>n("github")),f("click",a,()=>n("gitea")),D(x,d),H()}export{M as F};
|
||||
|
|
@ -1 +1 @@
|
|||
const w=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function x(t){const s=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${_(t).map(a=>{const i=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(a);if(i)return s.push({name:i[1],matcher:i[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const c=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(a);if(c)return s.push({name:c[1],matcher:c[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!a)return;const n=a.split(/\[(.+?)\](?!\])/);return"/"+n.map((e,u)=>{if(u%2){if(e.startsWith("x+"))return h(String.fromCharCode(parseInt(e.slice(2),16)));if(e.startsWith("u+"))return h(String.fromCharCode(...e.slice(2).split("-").map(g=>parseInt(g,16))));const o=w.exec(e),[,l,p,m,d]=o;return s.push({name:m,matcher:d,optional:!!l,rest:!!p,chained:p?u===1&&n[0]==="":!1}),p?"([^]*?)":l?"([^/]*)?":"([^/]+?)"}return h(e)}).join("")}).join("")}/?$`),params:s}}function $(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function _(t){return t.slice(1).split("/").filter($)}function j(t,s,f){const a={},i=t.slice(1),c=i.filter(r=>r!==void 0);let n=0;for(let r=0;r<s.length;r+=1){const e=s[r];let u=i[r-n];if(e.chained&&e.rest&&n&&(u=i.slice(r-n,r+1).filter(o=>o).join("/"),n=0),u===void 0){e.rest&&(a[e.name]="");continue}if(!e.matcher||f[e.matcher](u)){a[e.name]=u;const o=s[r+1],l=i[r+1];o&&!o.rest&&o.optional&&l&&e.chained&&(n=0),!o&&!l&&Object.keys(a).length===c.length&&(n=0);continue}if(e.optional&&e.chained){n++;continue}return}if(!n)return a}function h(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}const b=/\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;function k(t,s){return"/"+_(t).map(a=>a.replace(b,(i,c,n,r)=>{const e=s[r];if(!e){if(c||n&&e!==void 0)return"";throw new Error(`Missing parameter '${r}' in route ${t}`)}if(e.startsWith("/")||e.endsWith("/"))throw new Error(`Parameter '${r}' in route ${t} cannot start or end with a slash -- this would cause an invalid route like foo//bar`);return e})).filter(Boolean).join("/")}const v=globalThis.__sveltekit_1odpo7n?.base??"/ui",C=globalThis.__sveltekit_1odpo7n?.assets??v;export{C as a,v as b,j as e,x as p,k as r};
|
||||
const w=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function x(t){const s=[];return{pattern:t==="/"?/^\/$/:new RegExp(`^${_(t).map(a=>{const i=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(a);if(i)return s.push({name:i[1],matcher:i[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const c=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(a);if(c)return s.push({name:c[1],matcher:c[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!a)return;const n=a.split(/\[(.+?)\](?!\])/);return"/"+n.map((e,u)=>{if(u%2){if(e.startsWith("x+"))return h(String.fromCharCode(parseInt(e.slice(2),16)));if(e.startsWith("u+"))return h(String.fromCharCode(...e.slice(2).split("-").map(g=>parseInt(g,16))));const o=w.exec(e),[,l,p,m,d]=o;return s.push({name:m,matcher:d,optional:!!l,rest:!!p,chained:p?u===1&&n[0]==="":!1}),p?"([^]*?)":l?"([^/]*)?":"([^/]+?)"}return h(e)}).join("")}).join("")}/?$`),params:s}}function $(t){return t!==""&&!/^\([^)]+\)$/.test(t)}function _(t){return t.slice(1).split("/").filter($)}function j(t,s,f){const a={},i=t.slice(1),c=i.filter(r=>r!==void 0);let n=0;for(let r=0;r<s.length;r+=1){const e=s[r];let u=i[r-n];if(e.chained&&e.rest&&n&&(u=i.slice(r-n,r+1).filter(o=>o).join("/"),n=0),u===void 0){e.rest&&(a[e.name]="");continue}if(!e.matcher||f[e.matcher](u)){a[e.name]=u;const o=s[r+1],l=i[r+1];o&&!o.rest&&o.optional&&l&&e.chained&&(n=0),!o&&!l&&Object.keys(a).length===c.length&&(n=0);continue}if(e.optional&&e.chained){n++;continue}return}if(!n)return a}function h(t){return t.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}const b=/\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;function k(t,s){return"/"+_(t).map(a=>a.replace(b,(i,c,n,r)=>{const e=s[r];if(!e){if(c||n&&e!==void 0)return"";throw new Error(`Missing parameter '${r}' in route ${t}`)}if(e.startsWith("/")||e.endsWith("/"))throw new Error(`Parameter '${r}' in route ${t} cannot start or end with a slash -- this would cause an invalid route like foo//bar`);return e})).filter(Boolean).join("/")}const v=globalThis.__sveltekit_2i6bzq?.base??"/ui",C=globalThis.__sveltekit_2i6bzq?.assets??v;export{C as a,v as b,j as e,x as p,k as r};
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +0,0 @@
|
|||
import{d,s as w,f as x}from"./BZ2rxtTc.js";import"./DsnmJJEf.js";import{i as k}from"./TJn6xDN9.js";import{p as b,l as _,q as c,h as v,f as y,t as h,b as E,c as B,k as z,m as L,d as M,r as j,g as T,e as U}from"./DniTuB_0.js";import{p as o}from"./DbNhg6mG.js";function q(e){if(!e)return"N/A";try{return(typeof e=="string"?new Date(e):e).toLocaleString()}catch{return"Invalid Date"}}function A(e,r="w-4 h-4"){return e==="gitea"?`<svg class="${r}" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 640 640"><path d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12" style="fill:#fff"/><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6M125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1m300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1" style="fill:#609926"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8s2 16.3 9.1 20c7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3s17.4 1.7 22.5-5.3c5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8z" style="fill:#609926"/></svg>`:e==="github"?`<div class="inline-flex ${r}"><svg class="${r} dark:hidden" width="98" height="96" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg><svg class="${r} hidden dark:block" width="98" height="96" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg></div>`:`<svg class="${r} text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>`}function C(e,r){if(e.repo_name)return e.repo_name;if(e.org_name)return e.org_name;if(e.enterprise_name)return e.enterprise_name;if(e.repo_id&&!e.repo_name&&r?.repositories){const n=r.repositories.find(t=>t.id===e.repo_id);return n?`${n.owner}/${n.name}`:"Unknown Entity"}if(e.org_id&&!e.org_name&&r?.organizations){const n=r.organizations.find(t=>t.id===e.org_id);return n&&n.name?n.name:"Unknown Entity"}if(e.enterprise_id&&!e.enterprise_name&&r?.enterprises){const n=r.enterprises.find(t=>t.id===e.enterprise_id);return n&&n.name?n.name:"Unknown Entity"}return"Unknown Entity"}function H(e){return e.repo_id?"repository":e.org_id?"organization":e.enterprise_id?"enterprise":"unknown"}function P(e){return e.repo_id?d(`/repositories/${e.repo_id}`):e.org_id?d(`/organizations/${e.org_id}`):e.enterprise_id?d(`/enterprises/${e.enterprise_id}`):"#"}function V(e){e&&(e.scrollTop=e.scrollHeight)}function W(e){return{newPerPage:e,newCurrentPage:1}}function G(e){return e.pool_manager_status?.running?{text:"Running",variant:"success"}:{text:"Stopped",variant:"error"}}function J(e){switch(e.toLowerCase()){case"error":return{text:"Error",variant:"error"};case"warning":return{text:"Warning",variant:"warning"};case"info":return{text:"Info",variant:"info"};default:return{text:e,variant:"info"}}}function l(e,r,n){if(!r.trim())return e;const t=r.toLowerCase();return e.filter(a=>typeof n=="function"?n(a).toLowerCase().includes(t):n.some(i=>a[i]?.toString().toLowerCase().includes(t)))}function K(e,r){return l(e,r,["name","owner"])}function O(e,r){return l(e,r,["name"])}function Q(e,r){return l(e,r,n=>[n.name||"",n.description||"",n.endpoint?.name||""].join(" "))}function X(e,r){return l(e,r,["name","description","base_url","api_base_url"])}function Y(e,r,n){return e.slice((r-1)*n,r*n)}var I=y("<span> </span>");function Z(e,r){b(r,!1);const n=L();let t=o(r,"variant",8,"gray"),a=o(r,"size",8,"sm"),i=o(r,"text",8),g=o(r,"ring",8,!1);const u={success:"bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200",error:"bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200",warning:"bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200",info:"bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200",gray:"bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200",blue:"bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200",green:"bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200",red:"bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200",yellow:"bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200",secondary:"bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200"},f={success:"ring-green-600/20 dark:ring-green-400/30",error:"ring-red-600/20 dark:ring-red-400/30",warning:"ring-yellow-600/20 dark:ring-yellow-400/30",info:"ring-blue-600/20 dark:ring-blue-400/30",gray:"ring-gray-500/20 dark:ring-gray-400/30",blue:"ring-blue-600/20 dark:ring-blue-400/30",green:"ring-green-600/20 dark:ring-green-400/30",red:"ring-red-600/20 dark:ring-red-400/30",yellow:"ring-yellow-600/20 dark:ring-yellow-400/30",secondary:"ring-gray-500/20 dark:ring-gray-400/30"},p={sm:"px-2 py-1 text-xs",md:"px-2.5 py-0.5 text-xs"};_(()=>(c(t()),c(a()),c(g())),()=>{z(n,["inline-flex items-center rounded-full font-semibold",u[t()],p[a()],g()?`ring-1 ring-inset ${f[t()]}`:""].filter(Boolean).join(" "))}),v(),k();var s=I(),m=M(s,!0);j(s),h(()=>{w(s,1,x(T(n))),U(m,i())}),E(e,s),B()}export{Z as B,X as a,q as b,W as c,J as d,C as e,Q as f,A as g,l as h,H as i,P as j,G as k,O as l,K as m,Y as p,V as s};
|
||||
|
|
@ -1 +0,0 @@
|
|||
import"./DsnmJJEf.js";import{i as E}from"./TJn6xDN9.js";import{p as H,E as L,f as h,t as f,b as c,c as z,d as e,r as a,s as x,e as d,z as M,D as q}from"./DniTuB_0.js";import{p as i,i as C}from"./DbNhg6mG.js";import{B as F}from"./BZ2rxtTc.js";var G=h('<div class="mt-4 sm:mt-0 flex items-center space-x-4"><!></div>'),I=h('<div class="sm:flex sm:items-center sm:justify-between"><div><h1 class="text-2xl font-bold text-gray-900 dark:text-white"> </h1> <p class="mt-2 text-sm text-gray-700 dark:text-gray-300"> </p></div> <!></div>');function S(u,t){H(t,!1);const _=L();let b=i(t,"title",8),k=i(t,"description",8),v=i(t,"actionLabel",8,null),g=i(t,"showAction",8,!0);function w(){_("action")}E();var r=I(),s=e(r),o=e(s),y=e(o,!0);a(o);var m=x(o,2),A=e(m,!0);a(m),a(s);var P=x(s,2);{var j=n=>{var l=G(),B=e(l);F(B,{variant:"primary",icon:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />',$$events:{click:w},children:(D,J)=>{M();var p=q();f(()=>d(p,v())),c(D,p)},$$slots:{default:!0}}),a(l),c(n,l)};C(P,n=>{g()&&v()&&n(j)})}a(r),f(()=>{d(y,b()),d(A,k())}),c(u,r),z()}export{S as P};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as ae}from"./TJn6xDN9.js";import{p as se,E as re,l as M,q as ie,k as r,g as t,m as k,h as le,f as p,d as v,s as A,r as f,b as l,c as oe,A as T,a as B,z as q,D as V,t as E,e as F,u as ne}from"./DniTuB_0.js";import{p as N,i as m}from"./DbNhg6mG.js";import{g as h,B as G}from"./BZ2rxtTc.js";import{t as y}from"./CBJzOE8U.js";import{e as de}from"./BZiHL9L3.js";var ce=p('<div class="flex items-center"><div class="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600 mr-2"></div> <span class="text-sm text-gray-500 dark:text-gray-400">Checking...</span></div>'),ve=p('<div class="ml-4 text-xs text-gray-500 dark:text-gray-400"> </div>'),fe=p('<div class="flex items-center"><svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg> <span class="text-sm text-green-700 dark:text-green-300">Webhook installed</span></div> <!>',1),he=p('<div class="flex items-center"><svg class="w-4 h-4 text-gray-400 mr-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm0-2a6 6 0 100-12 6 6 0 000 12zm0-10a1 1 0 011 1v3a1 1 0 01-2 0V7a1 1 0 011-1z" clip-rule="evenodd"></path></svg> <span class="text-sm text-gray-500 dark:text-gray-400">No webhook installed</span></div>'),ue=p('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="flex items-center justify-between"><div><h3 class="text-lg font-medium text-gray-900 dark:text-white">Webhook Status</h3> <div class="mt-1 flex items-center"><!></div></div> <div class="flex space-x-2"><!></div></div></div></div>');function _e(H,g){se(g,!1);const x=k();let u=N(g,"entityType",8),s=N(g,"entityId",8),R=N(g,"entityName",8),i=k(null),o=k(!1),b=k(!0);const O=re();async function _(){if(s())try{r(b,!0),u()==="repository"?r(i,await h.getRepositoryWebhookInfo(s())):r(i,await h.getOrganizationWebhookInfo(s()))}catch(e){e&&typeof e=="object"&&"response"in e&&e.response?.status===404?r(i,null):(console.warn("Failed to check webhook status:",e),r(i,null))}finally{r(b,!1)}}async function J(){if(s())try{r(o,!0),u()==="repository"?await h.installRepositoryWebhook(s()):await h.installOrganizationWebhook(s()),y.success("Webhook Installed",`Webhook for ${u()} ${R()} has been installed successfully.`),await _(),O("webhookStatusChanged",{installed:!0})}catch(e){y.error("Webhook Installation Failed",e instanceof Error?e.message:"Failed to install webhook.")}finally{r(o,!1)}}async function K(){if(s())try{r(o,!0),u()==="repository"?await h.uninstallRepositoryWebhook(s()):await h.uninstallOrganizationWebhook(s()),y.success("Webhook Uninstalled",`Webhook for ${u()} ${R()} has been uninstalled successfully.`),await _(),O("webhookStatusChanged",{installed:!1})}catch(e){y.error("Webhook Uninstall Failed",de(e))}finally{r(o,!1)}}M(()=>ie(s()),()=>{s()&&_()}),M(()=>t(i),()=>{r(x,t(i)&&t(i).active)}),le(),ae();var w=ue(),P=v(w),j=v(P),W=v(j),D=A(v(W),2),Q=v(D);{var X=e=>{var d=ce();l(e,d)},Y=e=>{var d=T(),z=B(d);{var I=a=>{var n=fe(),C=A(B(n),2);{var c=U=>{var $=ve(),te=v($);f($),E(()=>F(te,`URL: ${t(i),ne(()=>t(i).url||"N/A")??""}`)),l(U,$)};m(C,U=>{t(i)&&U(c)})}l(a,n)},S=a=>{var n=he();l(a,n)};m(z,a=>{t(x)?a(I):a(S,!1)},!0)}l(e,d)};m(Q,e=>{t(b)?e(X):e(Y,!1)})}f(D),f(W);var L=A(W,2),Z=v(L);{var ee=e=>{var d=T(),z=B(d);{var I=a=>{G(a,{variant:"danger",size:"sm",get disabled(){return t(o)},$$events:{click:K},children:(n,C)=>{q();var c=V();E(()=>F(c,t(o)?"Uninstalling...":"Uninstall")),l(n,c)},$$slots:{default:!0}})},S=a=>{G(a,{variant:"primary",size:"sm",get disabled(){return t(o)},$$events:{click:J},children:(n,C)=>{q();var c=V();E(()=>F(c,t(o)?"Installing...":"Install Webhook")),l(n,c)},$$slots:{default:!0}})};m(z,a=>{t(x)?a(I):a(S,!1)})}l(e,d)};m(Z,e=>{t(b)||e(ee)})}f(L),f(j),f(P),f(w),l(H,w),oe()}export{_e as W};
|
||||
import"./DsnmJJEf.js";import{i as ae}from"./TJn6xDN9.js";import{p as se,E as re,l as M,q as ie,k as r,g as t,m as k,h as le,f as p,d as v,s as A,r as f,b as l,c as oe,A as T,a as B,z as q,D as V,t as E,e as F,u as ne}from"./DniTuB_0.js";import{p as N,i as m}from"./DbNhg6mG.js";import{g as h,B as G}from"./DSfKzFV1.js";import{t as y}from"./CBJzOE8U.js";import{e as de}from"./BZiHL9L3.js";var ce=p('<div class="flex items-center"><div class="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600 mr-2"></div> <span class="text-sm text-gray-500 dark:text-gray-400">Checking...</span></div>'),ve=p('<div class="ml-4 text-xs text-gray-500 dark:text-gray-400"> </div>'),fe=p('<div class="flex items-center"><svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path></svg> <span class="text-sm text-green-700 dark:text-green-300">Webhook installed</span></div> <!>',1),he=p('<div class="flex items-center"><svg class="w-4 h-4 text-gray-400 mr-2" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm0-2a6 6 0 100-12 6 6 0 000 12zm0-10a1 1 0 011 1v3a1 1 0 01-2 0V7a1 1 0 011-1z" clip-rule="evenodd"></path></svg> <span class="text-sm text-gray-500 dark:text-gray-400">No webhook installed</span></div>'),ue=p('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="flex items-center justify-between"><div><h3 class="text-lg font-medium text-gray-900 dark:text-white">Webhook Status</h3> <div class="mt-1 flex items-center"><!></div></div> <div class="flex space-x-2"><!></div></div></div></div>');function _e(H,g){se(g,!1);const x=k();let u=N(g,"entityType",8),s=N(g,"entityId",8),R=N(g,"entityName",8),i=k(null),o=k(!1),b=k(!0);const O=re();async function _(){if(s())try{r(b,!0),u()==="repository"?r(i,await h.getRepositoryWebhookInfo(s())):r(i,await h.getOrganizationWebhookInfo(s()))}catch(e){e&&typeof e=="object"&&"response"in e&&e.response?.status===404?r(i,null):(console.warn("Failed to check webhook status:",e),r(i,null))}finally{r(b,!1)}}async function J(){if(s())try{r(o,!0),u()==="repository"?await h.installRepositoryWebhook(s()):await h.installOrganizationWebhook(s()),y.success("Webhook Installed",`Webhook for ${u()} ${R()} has been installed successfully.`),await _(),O("webhookStatusChanged",{installed:!0})}catch(e){y.error("Webhook Installation Failed",e instanceof Error?e.message:"Failed to install webhook.")}finally{r(o,!1)}}async function K(){if(s())try{r(o,!0),u()==="repository"?await h.uninstallRepositoryWebhook(s()):await h.uninstallOrganizationWebhook(s()),y.success("Webhook Uninstalled",`Webhook for ${u()} ${R()} has been uninstalled successfully.`),await _(),O("webhookStatusChanged",{installed:!1})}catch(e){y.error("Webhook Uninstall Failed",de(e))}finally{r(o,!1)}}M(()=>ie(s()),()=>{s()&&_()}),M(()=>t(i),()=>{r(x,t(i)&&t(i).active)}),le(),ae();var w=ue(),P=v(w),j=v(P),W=v(j),D=A(v(W),2),Q=v(D);{var X=e=>{var d=ce();l(e,d)},Y=e=>{var d=T(),z=B(d);{var I=a=>{var n=fe(),C=A(B(n),2);{var c=U=>{var $=ve(),te=v($);f($),E(()=>F(te,`URL: ${t(i),ne(()=>t(i).url||"N/A")??""}`)),l(U,$)};m(C,U=>{t(i)&&U(c)})}l(a,n)},S=a=>{var n=he();l(a,n)};m(z,a=>{t(x)?a(I):a(S,!1)},!0)}l(e,d)};m(Q,e=>{t(b)?e(X):e(Y,!1)})}f(D),f(W);var L=A(W,2),Z=v(L);{var ee=e=>{var d=T(),z=B(d);{var I=a=>{G(a,{variant:"danger",size:"sm",get disabled(){return t(o)},$$events:{click:K},children:(n,C)=>{q();var c=V();E(()=>F(c,t(o)?"Uninstalling...":"Uninstall")),l(n,c)},$$slots:{default:!0}})},S=a=>{G(a,{variant:"primary",size:"sm",get disabled(){return t(o)},$$events:{click:J},children:(n,C)=>{q();var c=V();E(()=>F(c,t(o)?"Installing...":"Install Webhook")),l(n,c)},$$slots:{default:!0}})};m(z,a=>{t(x)?a(I):a(S,!1)})}l(e,d)};m(Z,e=>{t(b)||e(ee)})}f(L),f(j),f(P),f(w),l(H,w),oe()}export{_e as W};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import"./TJn6xDN9.js";import{f as l,s as h,d as n,r as f,t as N,e as w,b as r,A as x,a as y}from"./DniTuB_0.js";import{p,i as b}from"./DbNhg6mG.js";import{s as O}from"./BZ2rxtTc.js";var P=l('<div class="absolute top-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-t-gray-900"></div>'),Q=l('<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-900"></div>'),R=l('<div class="absolute right-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-l-gray-900"></div>'),S=l('<div class="absolute left-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-r-gray-900"></div>'),U=l('<div class="relative group"><svg class="w-3 h-3 text-gray-400 cursor-help" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> <div><div class="font-semibold mb-1"> </div> <div class="text-gray-300"> </div> <!></div></div>');function $(k,s){let z=p(s,"title",8),M=p(s,"content",8),t=p(s,"position",8,"top"),T=p(s,"width",8,"w-80");var m=U(),u=h(n(m),2),_=n(u),j=n(_,!0);f(_);var c=h(_,2),A=n(c,!0);f(c);var B=h(c,2);{var C=a=>{var i=P();r(a,i)},q=a=>{var i=x(),D=y(i);{var E=o=>{var v=Q();r(o,v)},F=o=>{var v=x(),G=y(v);{var H=e=>{var d=R();r(e,d)},I=e=>{var d=x(),J=y(d);{var K=g=>{var L=S();r(g,L)};b(J,g=>{t()==="right"&&g(K)},!0)}r(e,d)};b(G,e=>{t()==="left"?e(H):e(I,!1)},!0)}r(o,v)};b(D,o=>{t()==="bottom"?o(E):o(F,!1)},!0)}r(a,i)};b(B,a=>{t()==="top"?a(C):a(q,!1)})}f(u),f(m),N(()=>{O(u,1,`absolute ${t()==="top"?"bottom-full":t()==="bottom"?"top-full":t()==="left"?"right-full top-1/2 -translate-y-1/2":"left-full top-1/2 -translate-y-1/2"} left-1/2 transform -translate-x-1/2 ${t()==="top"?"mb-2":t()==="bottom"?"mt-2":"mx-2"} ${T()??""} p-3 bg-gray-900 text-white text-xs rounded-lg shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50`),w(j,z()),w(A,M())}),r(k,m)}export{$ as T};
|
||||
import"./DsnmJJEf.js";import"./TJn6xDN9.js";import{f as l,s as h,d as n,r as f,t as N,e as w,b as r,A as x,a as y}from"./DniTuB_0.js";import{p,i as b}from"./DbNhg6mG.js";import{s as O}from"./DSfKzFV1.js";var P=l('<div class="absolute top-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-t-gray-900"></div>'),Q=l('<div class="absolute bottom-full left-1/2 transform -translate-x-1/2 border-4 border-transparent border-b-gray-900"></div>'),R=l('<div class="absolute right-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-l-gray-900"></div>'),S=l('<div class="absolute left-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-r-gray-900"></div>'),U=l('<div class="relative group"><svg class="w-3 h-3 text-gray-400 cursor-help" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> <div><div class="font-semibold mb-1"> </div> <div class="text-gray-300"> </div> <!></div></div>');function $(k,s){let z=p(s,"title",8),M=p(s,"content",8),t=p(s,"position",8,"top"),T=p(s,"width",8,"w-80");var m=U(),u=h(n(m),2),_=n(u),j=n(_,!0);f(_);var c=h(_,2),A=n(c,!0);f(c);var B=h(c,2);{var C=a=>{var i=P();r(a,i)},q=a=>{var i=x(),D=y(i);{var E=o=>{var v=Q();r(o,v)},F=o=>{var v=x(),G=y(v);{var H=e=>{var d=R();r(e,d)},I=e=>{var d=x(),J=y(d);{var K=g=>{var L=S();r(g,L)};b(J,g=>{t()==="right"&&g(K)},!0)}r(e,d)};b(G,e=>{t()==="left"?e(H):e(I,!1)},!0)}r(o,v)};b(D,o=>{t()==="bottom"?o(E):o(F,!1)},!0)}r(a,i)};b(B,a=>{t()==="top"?a(C):a(q,!1)})}f(u),f(m),N(()=>{O(u,1,`absolute ${t()==="top"?"bottom-full":t()==="bottom"?"top-full":t()==="left"?"right-full top-1/2 -translate-y-1/2":"left-full top-1/2 -translate-y-1/2"} left-1/2 transform -translate-x-1/2 ${t()==="top"?"mb-2":t()==="bottom"?"mt-2":"mx-2"} ${T()??""} p-3 bg-gray-900 text-white text-xs rounded-lg shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50`),w(j,z()),w(A,M())}),r(k,m)}export{$ as T};
|
||||
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/DGZKesLN.js
Normal file
1
webapp/assets/_app/immutable/chunks/DGZKesLN.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as D}from"./TJn6xDN9.js";import{p as E,E as B,l as t,q as s,g as e,m as o,h as P,f as T,t as q,i as S,b as F,c as G,u as I,d as _,k as a,r as z}from"./DniTuB_0.js";import{i as J,h as K,s as N,j as O}from"./DSfKzFV1.js";import{l as j,p as l}from"./DbNhg6mG.js";var Q=T('<button><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><!></svg></button>');function Z(C,i){const M=j(i,["children","$$slots","$$events","$$legacy"]),L=j(M,["action","disabled","title","ariaLabel","size"]);E(i,!1);const u=o(),h=o(),k=o(),f=o(),g=o(),v=o(),n=o(),m=o(),b=o(),A=B();let r=l(i,"action",8,"edit"),x=l(i,"disabled",8,!1),w=l(i,"title",8,""),y=l(i,"ariaLabel",8,""),c=l(i,"size",8,"md");function H(){x()||A("click")}t(()=>{},()=>{a(u,"transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50")}),t(()=>s(c()),()=>{a(h,{sm:"p-1",md:"p-2"}[c()])}),t(()=>s(r()),()=>{a(k,{edit:"text-indigo-600 dark:text-indigo-400 hover:text-indigo-900 dark:hover:text-indigo-300 focus:ring-indigo-500",delete:"text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 focus:ring-red-500",view:"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300 focus:ring-gray-500",add:"text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300 focus:ring-green-500",copy:"text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 focus:ring-blue-500",download:"text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 focus:ring-blue-500"}[r()])}),t(()=>s(c()),()=>{a(f,c()==="sm"?"h-4 w-4":"h-5 w-5")}),t(()=>(e(u),e(h),e(k)),()=>{a(g,[e(u),e(h),e(k)].join(" "))}),t(()=>{},()=>{a(v,{edit:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />',delete:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />',view:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />',add:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />',copy:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />',download:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />'})}),t(()=>{},()=>{a(n,{edit:"Edit",delete:"Delete",view:"View",add:"Add",copy:"Clone",download:"Download"})}),t(()=>(s(w()),e(n),s(r())),()=>{a(m,w()||e(n)[r()])}),t(()=>(s(y()),e(n),s(r())),()=>{a(b,y()||`${e(n)[r()]} item`)}),P(),D();var d=Q();J(d,()=>({type:"button",class:e(g),disabled:x(),title:e(m),"aria-label":e(b),...L}));var p=_(d),V=_(p);K(V,()=>(e(v),s(r()),I(()=>e(v)[r()])),!0),z(p),z(d),q(()=>N(p,0,O(e(f)))),S("click",d,H),F(C,d),G()}export{Z as A};
|
||||
7
webapp/assets/_app/immutable/chunks/DSfKzFV1.js
Normal file
7
webapp/assets/_app/immutable/chunks/DSfKzFV1.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
import"./DsnmJJEf.js";import{i as R}from"./TJn6xDN9.js";import{p as j,l as w,h as A,f as g,t as k,b as v,c as B,s as D,d as u,k as _,m as y,r as m,q as f,u as h,g as d,e as U}from"./DniTuB_0.js";import{p as o,i as F}from"./DbNhg6mG.js";import{c as b,s as G,d as n}from"./BZ2rxtTc.js";var H=g('<div class="text-sm text-gray-500 dark:text-gray-400 truncate"> </div>'),J=g('<div class="w-full min-w-0 text-sm font-medium"><a> </a><!></div>');function V(x,a){j(a,!1);const i=y(),p=y();let e=o(a,"item",8),s=o(a,"entityType",8,"repository"),E=o(a,"showOwner",8,!1),I=o(a,"showId",8,!1),z=o(a,"fontMono",8,!1);function C(){if(!e())return"Unknown";switch(s()){case"repository":return E()?`${e().owner||"Unknown"}/${e().name||"Unknown"}`:e().name||"Unknown";case"organization":case"enterprise":return e().name||"Unknown";case"pool":return I()?e().id||"Unknown":e().name||"Unknown";case"scaleset":return e().name||"Unknown";case"instance":return e().name||"Unknown";case"template":return e().name||"Unknown";default:return e().name||e().id||"Unknown"}}function M(){if(!e())return"#";let t;switch(s()){case"instance":t=e().name;break;default:t=e().id||e().name;break}if(!t)return"#";switch(s()){case"repository":return n(`/repositories/${t}`);case"organization":return n(`/organizations/${t}`);case"enterprise":return n(`/enterprises/${t}`);case"pool":return n(`/pools/${t}`);case"scaleset":return n(`/scalesets/${t}`);case"instance":return n(`/instances/${encodeURIComponent(t)}`);case"template":return n(`/templates/${t}`);default:return"#"}}w(()=>{},()=>{_(i,C())}),w(()=>{},()=>{_(p,M())}),A(),R();var c=J(),r=u(c),N=u(r,!0);m(r);var O=D(r);{var T=t=>{var l=H(),q=u(l,!0);m(l),k(()=>U(q,(f(e()),h(()=>e().provider_id)))),v(t,l)};F(O,t=>{f(s()),f(e()),h(()=>s()==="instance"&&e()?.provider_id)&&t(T)})}m(c),k(()=>{b(r,"href",d(p)),G(r,1,`block w-full truncate text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300 ${z()?"font-mono":""}`),b(r,"title",d(i)),U(N,d(i))}),v(x,c),B()}export{V as E};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import"./DsnmJJEf.js";import{i as g}from"./TJn6xDN9.js";import{p as x,l as k,k as d,m as w,q as y,h as J,f as b,d as z,x as L,s as j,g as c,r as q,t as B,b as f,c as C}from"./DniTuB_0.js";import{p as o,i as E}from"./DbNhg6mG.js";import{c as n,s as M}from"./BZ2rxtTc.js";import{b as N}from"./CCQwxxp9.js";var O=b('<div class="absolute top-2 right-2"><svg class="w-4 h-4 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path></svg></div>'),S=b('<div class="relative"><textarea style="tab-size: 2;" spellcheck="false"></textarea> <!></div>');function I(m,r){x(r,!1);let t=o(r,"value",12,""),p=o(r,"placeholder",8,"{}"),u=o(r,"rows",8,4),i=o(r,"disabled",8,!1),a=w(!0);k(()=>y(t()),()=>{if(t().trim())try{JSON.parse(t()),d(a,!0)}catch{d(a,!1)}else d(a,!0)}),J(),g();var l=S(),e=z(l);L(e);var v=j(e,2);{var h=s=>{var _=O();f(s,_)};E(v,s=>{c(a)||s(h)})}q(l),B(()=>{n(e,"placeholder",p()),n(e,"rows",u()),e.disabled=i(),M(e,1,`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 font-mono text-sm resize-none
|
||||
import"./DsnmJJEf.js";import{i as g}from"./TJn6xDN9.js";import{p as x,l as k,k as d,m as w,q as y,h as J,f as b,d as z,x as L,s as j,g as c,r as q,t as B,b as f,c as C}from"./DniTuB_0.js";import{p as o,i as E}from"./DbNhg6mG.js";import{c as n,s as M}from"./DSfKzFV1.js";import{b as N}from"./CCQwxxp9.js";var O=b('<div class="absolute top-2 right-2"><svg class="w-4 h-4 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path></svg></div>'),S=b('<div class="relative"><textarea style="tab-size: 2;" spellcheck="false"></textarea> <!></div>');function I(m,r){x(r,!1);let t=o(r,"value",12,""),p=o(r,"placeholder",8,"{}"),u=o(r,"rows",8,4),i=o(r,"disabled",8,!1),a=w(!0);k(()=>y(t()),()=>{if(t().trim())try{JSON.parse(t()),d(a,!0)}catch{d(a,!1)}else d(a,!0)}),J(),g();var l=S(),e=z(l);L(e);var v=j(e,2);{var h=s=>{var _=O();f(s,_)};E(v,s=>{c(a)||s(h)})}q(l),B(()=>{n(e,"placeholder",p()),n(e,"rows",u()),e.disabled=i(),M(e,1,`w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 font-mono text-sm resize-none
|
||||
${c(a)?"border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white":"border-red-300 dark:border-red-600 bg-red-50 dark:bg-red-900/20 text-red-900 dark:text-red-100"}
|
||||
${i()?"opacity-50 cursor-not-allowed":""}
|
||||
`)}),N(e,t),f(m,l),C()}export{I as J};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import"./TJn6xDN9.js";import{f as k,d as a,s as m,r as i,t as g,e as f,b as v,z as p,D as z}from"./DniTuB_0.js";import{p as t,i as u}from"./DbNhg6mG.js";import{s as Y,h as Z,B as H}from"./BZ2rxtTc.js";var $=k('<div class="flex-shrink-0"><!></div>'),ee=k('<div class="mt-4 sm:mt-0 flex space-x-3"><!> <!></div>'),te=k('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="sm:flex sm:items-center sm:justify-between"><div class="flex items-center space-x-3"><!> <div><h1> </h1> <p class="text-sm text-gray-500 dark:text-gray-400"> </p></div></div> <!></div></div></div>');function se(j,e){let E=t(e,"title",8),M=t(e,"subtitle",8),D=t(e,"forgeIcon",8,""),h=t(e,"onEdit",8,null),x=t(e,"onDelete",8,null),B=t(e,"editLabel",8,"Edit"),C=t(e,"deleteLabel",8,"Delete"),P=t(e,"editVariant",8,"secondary"),A=t(e,"deleteVariant",8,"danger"),q=t(e,"editDisabled",8,!1),F=t(e,"deleteDisabled",8,!1),G=t(e,"editIcon",8,"<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z'/>"),J=t(e,"deleteIcon",8,"<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16'/>"),K=t(e,"titleClass",8,"");var _=te(),y=a(_),w=a(y),b=a(w),I=a(b);{var N=l=>{var d=$(),c=a(d);Z(c,D),i(d),v(l,d)};u(I,l=>{D()&&l(N)})}var L=m(I,2),o=a(L),O=a(o,!0);i(o);var V=m(o,2),Q=a(V,!0);i(V),i(L),i(b);var R=m(b,2);{var S=l=>{var d=ee(),c=a(d);{var T=r=>{H(r,{get variant(){return P()},size:"md",get disabled(){return q()},get icon(){return G()},$$events:{click(...s){h()?.apply(this,s)}},children:(s,X)=>{p();var n=z();g(()=>f(n,B())),v(s,n)},$$slots:{default:!0}})};u(c,r=>{h()&&r(T)})}var U=m(c,2);{var W=r=>{H(r,{get variant(){return A()},size:"md",get disabled(){return F()},get icon(){return J()},$$events:{click(...s){x()?.apply(this,s)}},children:(s,X)=>{p();var n=z();g(()=>f(n,C())),v(s,n)},$$slots:{default:!0}})};u(U,r=>{x()&&r(W)})}i(d),v(l,d)};u(R,l=>{(h()||x())&&l(S)})}i(w),i(y),i(_),g(()=>{Y(o,1,`text-2xl font-bold text-gray-900 dark:text-white ${K()??""}`),f(O,E()),f(Q,M())}),v(j,_)}export{se as D};
|
||||
import"./DsnmJJEf.js";import"./TJn6xDN9.js";import{f as k,d as a,s as m,r as i,t as g,e as f,b as v,z as p,D as z}from"./DniTuB_0.js";import{p as t,i as u}from"./DbNhg6mG.js";import{s as Y,h as Z,B as H}from"./DSfKzFV1.js";var $=k('<div class="flex-shrink-0"><!></div>'),ee=k('<div class="mt-4 sm:mt-0 flex space-x-3"><!> <!></div>'),te=k('<div class="bg-white dark:bg-gray-800 shadow rounded-lg"><div class="px-4 py-5 sm:p-6"><div class="sm:flex sm:items-center sm:justify-between"><div class="flex items-center space-x-3"><!> <div><h1> </h1> <p class="text-sm text-gray-500 dark:text-gray-400"> </p></div></div> <!></div></div></div>');function se(j,e){let E=t(e,"title",8),M=t(e,"subtitle",8),D=t(e,"forgeIcon",8,""),h=t(e,"onEdit",8,null),x=t(e,"onDelete",8,null),B=t(e,"editLabel",8,"Edit"),C=t(e,"deleteLabel",8,"Delete"),P=t(e,"editVariant",8,"secondary"),A=t(e,"deleteVariant",8,"danger"),q=t(e,"editDisabled",8,!1),F=t(e,"deleteDisabled",8,!1),G=t(e,"editIcon",8,"<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z'/>"),J=t(e,"deleteIcon",8,"<path stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16'/>"),K=t(e,"titleClass",8,"");var _=te(),y=a(_),w=a(y),b=a(w),I=a(b);{var N=l=>{var d=$(),c=a(d);Z(c,D),i(d),v(l,d)};u(I,l=>{D()&&l(N)})}var L=m(I,2),o=a(L),O=a(o,!0);i(o);var V=m(o,2),Q=a(V,!0);i(V),i(L),i(b);var R=m(b,2);{var S=l=>{var d=ee(),c=a(d);{var T=r=>{H(r,{get variant(){return P()},size:"md",get disabled(){return q()},get icon(){return G()},$$events:{click(...s){h()?.apply(this,s)}},children:(s,X)=>{p();var n=z();g(()=>f(n,B())),v(s,n)},$$slots:{default:!0}})};u(c,r=>{h()&&r(T)})}var U=m(c,2);{var W=r=>{H(r,{get variant(){return A()},size:"md",get disabled(){return F()},get icon(){return J()},$$events:{click(...s){x()?.apply(this,s)}},children:(s,X)=>{p();var n=z();g(()=>f(n,C())),v(s,n)},$$slots:{default:!0}})};u(U,r=>{x()&&r(W)})}i(d),v(l,d)};u(R,l=>{(h()||x())&&l(S)})}i(w),i(y),i(_),g(()=>{Y(o,1,`text-2xl font-bold text-gray-900 dark:text-white ${K()??""}`),f(O,E()),f(Q,M())}),v(j,_)}export{se as D};
|
||||
|
|
@ -1 +1 @@
|
|||
import{F as w}from"./DniTuB_0.js";import{g as r}from"./BZ2rxtTc.js";const m=!0,z=m,I=()=>window.location.port==="5173",b={isAuthenticated:!1,user:null,loading:!0,needsInitialization:!1},n=w(b);function f(t,a,e=7){const i=new Date;i.setTime(i.getTime()+e*24*60*60*1e3),document.cookie=`${t}=${a};expires=${i.toUTCString()};path=/;SameSite=Lax`}function d(t){const a=t+"=",e=document.cookie.split(";");for(let i=0;i<e.length;i++){let o=e[i];for(;o.charAt(0)===" ";)o=o.substring(1,o.length);if(o.indexOf(a)===0)return o.substring(a.length,o.length)}return null}function g(t){document.cookie=`${t}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/`}const c={async login(t,a){try{n.update(i=>({...i,loading:!0}));const e=await r.login({username:t,password:a});z&&(f("garm_token",e.token),f("garm_user",t)),r.setToken(e.token),n.set({isAuthenticated:!0,user:t,loading:!1,needsInitialization:!1})}catch(e){throw n.update(i=>({...i,loading:!1})),e}},logout(){g("garm_token"),g("garm_user"),n.set({isAuthenticated:!1,user:null,loading:!1,needsInitialization:!1})},async init(){try{n.update(e=>({...e,loading:!0})),await c.checkInitializationStatus();const t=d("garm_token"),a=d("garm_user");if(t&&a&&(r.setToken(t),await c.checkAuth())){n.set({isAuthenticated:!0,user:a,loading:!1,needsInitialization:!1});return}n.update(e=>({...e,loading:!1,needsInitialization:!1}))}catch{n.update(a=>({...a,loading:!1}))}},async checkInitializationStatus(){try{const t={Accept:"application/json"},a=d("garm_token"),e=I();e&&a&&(t.Authorization=`Bearer ${a}`);const i=await fetch("/api/v1/login",{method:"GET",headers:t,credentials:e?"omit":"include"});if(!i.ok){if(i.status===409&&(await i.json()).error==="init_required")throw n.update(s=>({...s,needsInitialization:!0,loading:!1})),new Error("Initialization required");return}return}catch(t){if(t instanceof Error&&t.message==="Initialization required")throw t;return}},async checkAuth(){try{return await c.checkInitializationStatus(),await r.getControllerInfo(),!0}catch(t){return t instanceof Error&&t.message==="Initialization required"?!1:t?.response?.status===409&&t?.response?.data?.error==="init_required"?(n.update(a=>({...a,needsInitialization:!0,loading:!1})),!1):(c.logout(),!1)}},async initialize(t,a,e,i,o){try{n.update(u=>({...u,loading:!0}));const s=await r.firstRun({username:t,email:a,password:e,full_name:i||t});await c.login(t,e);const l=window.location.origin,h=o?.metadataUrl||`${l}/api/v1/metadata`,p=o?.callbackUrl||`${l}/api/v1/callbacks`,k=o?.webhookUrl||`${l}/webhooks`;await r.updateController({metadata_url:h,callback_url:p,webhook_url:k}),n.update(u=>({...u,needsInitialization:!1}))}catch(s){throw n.update(l=>({...l,loading:!1})),s}}};export{n as a,c as b};
|
||||
import{F as w}from"./DniTuB_0.js";import{g as r}from"./DSfKzFV1.js";const m=!0,z=m,I=()=>window.location.port==="5173",b={isAuthenticated:!1,user:null,loading:!0,needsInitialization:!1},n=w(b);function f(t,a,e=7){const i=new Date;i.setTime(i.getTime()+e*24*60*60*1e3),document.cookie=`${t}=${a};expires=${i.toUTCString()};path=/;SameSite=Lax`}function d(t){const a=t+"=",e=document.cookie.split(";");for(let i=0;i<e.length;i++){let o=e[i];for(;o.charAt(0)===" ";)o=o.substring(1,o.length);if(o.indexOf(a)===0)return o.substring(a.length,o.length)}return null}function g(t){document.cookie=`${t}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/`}const c={async login(t,a){try{n.update(i=>({...i,loading:!0}));const e=await r.login({username:t,password:a});z&&(f("garm_token",e.token),f("garm_user",t)),r.setToken(e.token),n.set({isAuthenticated:!0,user:t,loading:!1,needsInitialization:!1})}catch(e){throw n.update(i=>({...i,loading:!1})),e}},logout(){g("garm_token"),g("garm_user"),n.set({isAuthenticated:!1,user:null,loading:!1,needsInitialization:!1})},async init(){try{n.update(e=>({...e,loading:!0})),await c.checkInitializationStatus();const t=d("garm_token"),a=d("garm_user");if(t&&a&&(r.setToken(t),await c.checkAuth())){n.set({isAuthenticated:!0,user:a,loading:!1,needsInitialization:!1});return}n.update(e=>({...e,loading:!1,needsInitialization:!1}))}catch{n.update(a=>({...a,loading:!1}))}},async checkInitializationStatus(){try{const t={Accept:"application/json"},a=d("garm_token"),e=I();e&&a&&(t.Authorization=`Bearer ${a}`);const i=await fetch("/api/v1/login",{method:"GET",headers:t,credentials:e?"omit":"include"});if(!i.ok){if(i.status===409&&(await i.json()).error==="init_required")throw n.update(s=>({...s,needsInitialization:!0,loading:!1})),new Error("Initialization required");return}return}catch(t){if(t instanceof Error&&t.message==="Initialization required")throw t;return}},async checkAuth(){try{return await c.checkInitializationStatus(),await r.getControllerInfo(),!0}catch(t){return t instanceof Error&&t.message==="Initialization required"?!1:t?.response?.status===409&&t?.response?.data?.error==="init_required"?(n.update(a=>({...a,needsInitialization:!0,loading:!1})),!1):(c.logout(),!1)}},async initialize(t,a,e,i,o){try{n.update(u=>({...u,loading:!0}));const s=await r.firstRun({username:t,email:a,password:e,full_name:i||t});await c.login(t,e);const l=window.location.origin,h=o?.metadataUrl||`${l}/api/v1/metadata`,p=o?.callbackUrl||`${l}/api/v1/callbacks`,k=o?.webhookUrl||`${l}/webhooks`;await r.updateController({metadata_url:h,callback_url:p,webhook_url:k}),n.update(u=>({...u,needsInitialization:!1}))}catch(s){throw n.update(l=>({...l,loading:!1})),s}}};export{n as a,c as b};
|
||||
|
|
@ -1 +1 @@
|
|||
import{s as e}from"./HMJxCnAR.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p};
|
||||
import{s as e}from"./kW9-6GPQ.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p};
|
||||
1
webapp/assets/_app/immutable/chunks/Dyp1NLoF.js
Normal file
1
webapp/assets/_app/immutable/chunks/Dyp1NLoF.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as k}from"./TJn6xDN9.js";import{p as c,l as u,q as g,h as f,f as m,t as p,b as w,c as _,k as v,m as h,d as z,r as B,g as j,e as q}from"./DniTuB_0.js";import{s as V,j as A}from"./DSfKzFV1.js";import{p as a}from"./DbNhg6mG.js";var C=m("<span> </span>");function I(d,e){c(e,!1);const n=h();let t=a(e,"variant",8,"gray"),l=a(e,"size",8,"sm"),i=a(e,"text",8),s=a(e,"ring",8,!1);const o={success:"bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200",error:"bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200",warning:"bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200",info:"bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200",gray:"bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200",blue:"bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200",green:"bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200",red:"bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200",yellow:"bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200",secondary:"bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200"},b={success:"ring-green-600/20 dark:ring-green-400/30",error:"ring-red-600/20 dark:ring-red-400/30",warning:"ring-yellow-600/20 dark:ring-yellow-400/30",info:"ring-blue-600/20 dark:ring-blue-400/30",gray:"ring-gray-500/20 dark:ring-gray-400/30",blue:"ring-blue-600/20 dark:ring-blue-400/30",green:"ring-green-600/20 dark:ring-green-400/30",red:"ring-red-600/20 dark:ring-red-400/30",yellow:"ring-yellow-600/20 dark:ring-yellow-400/30",secondary:"ring-gray-500/20 dark:ring-gray-400/30"},y={sm:"px-2 py-1 text-xs",md:"px-2.5 py-0.5 text-xs"};u(()=>(g(t()),g(l()),g(s())),()=>{v(n,["inline-flex items-center rounded-full font-semibold",o[t()],y[l()],s()?`ring-1 ring-inset ${b[t()]}`:""].filter(Boolean).join(" "))}),f(),k();var r=C(),x=z(r,!0);B(r),p(()=>{V(r,1,A(j(n))),q(x,i())}),w(d,r),_()}export{I as B};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as _}from"./TJn6xDN9.js";import{p as k,f as E,t as C,u as i,q as t,e as f,b as P,c as j,s as q,d as l,r as o}from"./DniTuB_0.js";import{c as z}from"./BZ2rxtTc.js";import{p as n}from"./DbNhg6mG.js";import{j as x,e as c,i as u}from"./CTcPpzia.js";var N=E('<div class="flex flex-col"><a class="text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300"> </a> <span class="text-xs text-gray-500 dark:text-gray-400 capitalize"> </span></div>');function F(d,r){k(r,!1);let e=n(r,"item",8),m=n(r,"eagerCache",8,null);_();var s=N(),a=l(s),v=l(a,!0);o(a);var p=q(a,2),g=l(p,!0);o(p),o(s),C((h,b,y)=>{z(a,"href",h),f(v,b),f(g,y)},[()=>(t(x),t(e()),i(()=>x(e()))),()=>(t(c),t(e()),t(m()),i(()=>c(e(),m()))),()=>(t(u),t(e()),i(()=>u(e())))]),P(d,s),j()}export{F as P};
|
||||
import"./DsnmJJEf.js";import{i as _}from"./TJn6xDN9.js";import{p as k,f as E,t as C,u as i,q as t,e as f,b as P,c as j,s as q,d as l,r as o}from"./DniTuB_0.js";import{c as z}from"./DSfKzFV1.js";import{p as n}from"./DbNhg6mG.js";import{j as x,e as c,i as u}from"./BC4TpgBU.js";var N=E('<div class="flex flex-col"><a class="text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300"> </a> <span class="text-xs text-gray-500 dark:text-gray-400 capitalize"> </span></div>');function F(d,r){k(r,!1);let e=n(r,"item",8),m=n(r,"eagerCache",8,null);_();var s=N(),a=l(s),v=l(a,!0);o(a);var p=q(a,2),g=l(p,!0);o(p),o(s),C((h,b,y)=>{z(a,"href",h),f(v,b),f(g,y)},[()=>(t(x),t(e()),i(()=>x(e()))),()=>(t(c),t(e()),t(m()),i(()=>c(e(),m()))),()=>(t(u),t(e()),i(()=>u(e())))]),P(d,s),j()}export{F as P};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1 +0,0 @@
|
|||
import"./DsnmJJEf.js";import{i as V}from"./TJn6xDN9.js";import{p as B,E as D,l as t,q as s,g as e,m as a,h as P,f as T,t as q,i as S,b as F,c as G,u as I,d as w,k as o,r as z}from"./DniTuB_0.js";import{e as J,h as K,s as N,f as O}from"./BZ2rxtTc.js";import{l as C,p as l}from"./DbNhg6mG.js";var Q=T('<button><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><!></svg></button>');function Z(j,i){const M=C(i,["children","$$slots","$$events","$$legacy"]),L=C(M,["action","disabled","title","ariaLabel","size"]);B(i,!1);const u=a(),h=a(),p=a(),v=a(),g=a(),f=a(),n=a(),m=a(),b=a(),A=D();let r=l(i,"action",8,"edit"),x=l(i,"disabled",8,!1),y=l(i,"title",8,""),_=l(i,"ariaLabel",8,""),c=l(i,"size",8,"md");function H(){x()||A("click")}t(()=>{},()=>{o(u,"transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50")}),t(()=>s(c()),()=>{o(h,{sm:"p-1",md:"p-2"}[c()])}),t(()=>s(r()),()=>{o(p,{edit:"text-indigo-600 dark:text-indigo-400 hover:text-indigo-900 dark:hover:text-indigo-300 focus:ring-indigo-500",delete:"text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 focus:ring-red-500",view:"text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300 focus:ring-gray-500",add:"text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300 focus:ring-green-500",copy:"text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 focus:ring-blue-500"}[r()])}),t(()=>s(c()),()=>{o(v,c()==="sm"?"h-4 w-4":"h-5 w-5")}),t(()=>(e(u),e(h),e(p)),()=>{o(g,[e(u),e(h),e(p)].join(" "))}),t(()=>{},()=>{o(f,{edit:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />',delete:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />',view:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />',add:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />',copy:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />'})}),t(()=>{},()=>{o(n,{edit:"Edit",delete:"Delete",view:"View",add:"Add",copy:"Clone"})}),t(()=>(s(y()),e(n),s(r())),()=>{o(m,y()||e(n)[r()])}),t(()=>(s(_()),e(n),s(r())),()=>{o(b,_()||`${e(n)[r()]} item`)}),P(),V();var d=Q();J(d,()=>({type:"button",class:e(g),disabled:x(),title:e(m),"aria-label":e(b),...L}));var k=w(d),E=w(k);K(E,()=>(e(f),s(r()),I(()=>e(f)[r()])),!0),z(k),z(d),q(()=>N(k,0,O(e(v)))),S("click",d,H),F(j,d),G()}export{Z as A};
|
||||
1
webapp/assets/_app/immutable/chunks/RtJp4Ifn.js
Normal file
1
webapp/assets/_app/immutable/chunks/RtJp4Ifn.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as F}from"./TJn6xDN9.js";import{p as G,E as I,f as x,t as _,b as r,c as J,d as s,r as i,s as k,u as K,e as f,A as N,a as O,z as Q,D as R}from"./DniTuB_0.js";import{p as o,i as b}from"./DbNhg6mG.js";import{e as S,f as T,B as U}from"./DSfKzFV1.js";var V=x('<div class="mt-4 sm:mt-0 flex items-center space-x-4"><!></div>'),W=x('<div class="mt-4 sm:mt-0 flex items-center space-x-4"><!></div>'),X=x('<div class="sm:flex sm:items-center sm:justify-between"><div><h1 class="text-2xl font-bold text-gray-900 dark:text-white"> </h1> <p class="mt-2 text-sm text-gray-700 dark:text-gray-300"> </p></div> <!></div>');function st(g,t){const w=S(t);G(t,!1);const y=I();let A=o(t,"title",8),P=o(t,"description",8),h=o(t,"actionLabel",8,null),j=o(t,"showAction",8,!0);function z(){y("action")}F();var n=X(),l=s(n),c=s(l),B=s(c,!0);i(c);var p=k(c,2),D=s(p,!0);i(p),i(l);var E=k(l,2);{var H=e=>{var a=V(),v=s(a);T(v,t,"actions",{}),i(a),r(e,a)},L=e=>{var a=N(),v=O(a);{var M=d=>{var m=W(),q=s(m);U(q,{variant:"primary",icon:'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />',$$events:{click:z},children:(C,Y)=>{Q();var u=R();_(()=>f(u,h())),r(C,u)},$$slots:{default:!0}}),i(m),r(d,m)};b(v,d=>{j()&&h()&&d(M)},!0)}r(e,a)};b(E,e=>{K(()=>w.actions)?e(H):e(L,!1)})}i(n),_(()=>{f(B,A()),f(D,P())}),r(g,n),J()}export{st as P};
|
||||
1
webapp/assets/_app/immutable/chunks/aK-A9Gop.js
Normal file
1
webapp/assets/_app/immutable/chunks/aK-A9Gop.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
function i(t){const n=["B","KB","MB","GB","TB"];let r=t,e=0;for(;r>=1024&&e<n.length-1;)r/=1024,e++;return`${r.toFixed(e===0?0:1)} ${n[e]}`}function o(t){if(!t)return"N/A";try{return new Date(t).toLocaleString()}catch{return t}}export{o as a,i as f};
|
||||
|
|
@ -1 +1 @@
|
|||
import{s as t,p as r}from"./HMJxCnAR.js";const e={get data(){return r.data},get error(){return r.error},get form(){return r.form},get params(){return r.params},get route(){return r.route},get state(){return r.state},get status(){return r.status},get url(){return r.url}};t.updated.check;const s=e;export{s as p};
|
||||
import{s as t,p as r}from"./kW9-6GPQ.js";const e={get data(){return r.data},get error(){return r.error},get form(){return r.form},get params(){return r.params},get route(){return r.route},get state(){return r.state},get status(){return r.status},get url(){return r.url}};t.updated.check;const s=e;export{s as p};
|
||||
File diff suppressed because one or more lines are too long
3
webapp/assets/_app/immutable/chunks/kW9-6GPQ.js
Normal file
3
webapp/assets/_app/immutable/chunks/kW9-6GPQ.js
Normal file
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/chunks/l9U2NoST.js
Normal file
1
webapp/assets/_app/immutable/chunks/l9U2NoST.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as u}from"./TJn6xDN9.js";import{p as v,E as m,f as h,d as r,r as d,i as t,b as k,c as g}from"./DniTuB_0.js";import{f as b}from"./DSfKzFV1.js";var w=h('<div class="fixed inset-0 bg-black/30 dark:bg-black/50 overflow-y-auto h-full w-full z-50 flex items-center justify-center p-4" role="dialog" aria-modal="true" tabindex="-1"><div class="relative mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-lg" role="document"><!></div></div>');function M(s,i){v(i,!1);const l=m();function n(){l("close")}function c(o){o.stopPropagation()}function f(o){o.key==="Escape"&&l("close")}u();var a=w(),e=r(a),p=r(e);b(p,i,"default",{}),d(e),d(a),t("click",e,c),t("click",a,n),t("keydown",a,f),k(s,a),g()}export{M};
|
||||
|
|
@ -1 +1 @@
|
|||
import"./DsnmJJEf.js";import{i as q}from"./TJn6xDN9.js";import{p as A,E as F,f as y,s as l,d as t,r as a,z as $,D as b,b as o,t as p,e as n,c as G}from"./DniTuB_0.js";import{p as v,i as H}from"./DbNhg6mG.js";import{M as I}from"./CHjY0Kaf.js";import{B as w}from"./BZ2rxtTc.js";var J=y('<p class="mt-1 font-medium text-gray-900 dark:text-white"> </p>'),K=y('<div class="max-w-xl w-full p-6"><div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 dark:bg-red-900 mb-4"><svg class="h-6 w-6 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path></svg></div> <div class="text-center"><h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white mb-2"> </h3> <div class="text-sm text-gray-500 dark:text-gray-400"><p> </p> <!></div></div> <div class="mt-6 flex justify-end space-x-3"><!> <!></div></div>');function W(D,s){A(s,!1);let M=v(s,"title",8),j=v(s,"message",8),g=v(s,"itemName",8,""),d=v(s,"loading",8,!1);const c=F();function B(){c("confirm")}q(),I(D,{$$events:{close:()=>c("close")},children:(C,O)=>{var m=K(),f=l(t(m),2),u=t(f),P=t(u,!0);a(u);var h=l(u,2),x=t(h),z=t(x,!0);a(x);var E=l(x,2);{var L=e=>{var i=J(),r=t(i,!0);a(i),p(()=>n(r,g())),o(e,i)};H(E,e=>{g()&&e(L)})}a(h),a(f);var _=l(f,2),k=t(_);w(k,{variant:"secondary",get disabled(){return d()},$$events:{click:()=>c("close")},children:(e,i)=>{$();var r=b("Cancel");o(e,r)},$$slots:{default:!0}});var N=l(k,2);w(N,{variant:"danger",get disabled(){return d()},get loading(){return d()},$$events:{click:B},children:(e,i)=>{$();var r=b();p(()=>n(r,d()?"Deleting...":"Delete")),o(e,r)},$$slots:{default:!0}}),a(_),a(m),p(()=>{n(P,M()),n(z,j())}),o(C,m)},$$slots:{default:!0}}),G()}export{W as D};
|
||||
import"./DsnmJJEf.js";import{i as q}from"./TJn6xDN9.js";import{p as A,E as F,f as y,s as l,d as t,r as a,z as $,D as b,b as o,t as p,e as n,c as G}from"./DniTuB_0.js";import{p as v,i as H}from"./DbNhg6mG.js";import{M as I}from"./l9U2NoST.js";import{B as w}from"./DSfKzFV1.js";var J=y('<p class="mt-1 font-medium text-gray-900 dark:text-white"> </p>'),K=y('<div class="max-w-xl w-full p-6"><div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 dark:bg-red-900 mb-4"><svg class="h-6 w-6 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path></svg></div> <div class="text-center"><h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-white mb-2"> </h3> <div class="text-sm text-gray-500 dark:text-gray-400"><p> </p> <!></div></div> <div class="mt-6 flex justify-end space-x-3"><!> <!></div></div>');function W(D,s){A(s,!1);let M=v(s,"title",8),j=v(s,"message",8),g=v(s,"itemName",8,""),d=v(s,"loading",8,!1);const c=F();function B(){c("confirm")}q(),I(D,{$$events:{close:()=>c("close")},children:(C,O)=>{var m=K(),f=l(t(m),2),u=t(f),P=t(u,!0);a(u);var h=l(u,2),x=t(h),z=t(x,!0);a(x);var E=l(x,2);{var L=e=>{var i=J(),r=t(i,!0);a(i),p(()=>n(r,g())),o(e,i)};H(E,e=>{g()&&e(L)})}a(h),a(f);var _=l(f,2),k=t(_);w(k,{variant:"secondary",get disabled(){return d()},$$events:{click:()=>c("close")},children:(e,i)=>{$();var r=b("Cancel");o(e,r)},$$slots:{default:!0}});var N=l(k,2);w(N,{variant:"danger",get disabled(){return d()},get loading(){return d()},$$events:{click:B},children:(e,i)=>{$();var r=b();p(()=>n(r,d()?"Deleting...":"Delete")),o(e,r)},$$slots:{default:!0}}),a(_),a(m),p(()=>{n(P,M()),n(z,j())}),o(C,m)},$$slots:{default:!0}}),G()}export{W as D};
|
||||
2
webapp/assets/_app/immutable/entry/app.BGzeJotz.js
Normal file
2
webapp/assets/_app/immutable/entry/app.BGzeJotz.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/entry/start.C5WiwcG-.js
Normal file
1
webapp/assets/_app/immutable/entry/start.C5WiwcG-.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import{l as o,a as r}from"../chunks/kW9-6GPQ.js";export{o as load_css,r as start};
|
||||
|
|
@ -1 +0,0 @@
|
|||
import{l as o,a as r}from"../chunks/HMJxCnAR.js";export{o as load_css,r as start};
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
import"../chunks/DsnmJJEf.js";import{i as h}from"../chunks/TJn6xDN9.js";import{p as c,f as l,a as v,t as u,b as _,c as d,d as s,r as e,s as g,e as p}from"../chunks/DniTuB_0.js";import{p as o}from"../chunks/Hb0uuDRx.js";var x=l("<h1> </h1> <p> </p>",1);function q(i,m){c(m,!1),h();var t=x(),r=v(t),f=s(r,!0);e(r);var a=g(r,2),n=s(a,!0);e(a),u(()=>{p(f,o.status),p(n,o.error?.message)}),_(i,t),d()}export{q as component};
|
||||
import"../chunks/DsnmJJEf.js";import{i as h}from"../chunks/TJn6xDN9.js";import{p as c,f as l,a as v,t as u,b as _,c as d,d as s,r as e,s as g,e as p}from"../chunks/DniTuB_0.js";import{p as o}from"../chunks/covROD4j.js";var x=l("<h1> </h1> <p> </p>",1);function q(i,m){c(m,!1),h();var t=x(),r=v(t),f=s(r,!0);e(r);var a=g(r,2),n=s(a,!0);e(a),u(()=>{p(f,o.status),p(n,o.error?.message)}),_(i,t),d()}export{q as component};
|
||||
|
|
@ -1 +1 @@
|
|||
import"../chunks/DsnmJJEf.js";import{i as Z}from"../chunks/TJn6xDN9.js";import{p as ee,o as ae,l as re,h as te,f as K,j as se,t as _,g as a,i as k,b as w,c as de,$ as oe,s as d,D as ie,m as f,d as r,u as q,q as B,k as i,r as t,z as D,e as I}from"../chunks/DniTuB_0.js";import{i as le,s as ne,a as ce}from"../chunks/DbNhg6mG.js";import{B as me,d as l,c as T,r as U}from"../chunks/BZ2rxtTc.js";import{b as C}from"../chunks/CCQwxxp9.js";import{p as ue}from"../chunks/D4Caz1gY.js";import{g as H}from"../chunks/HMJxCnAR.js";import{a as pe,b as ve}from"../chunks/1biM6o9g.js";import{e as fe}from"../chunks/BZiHL9L3.js";var ge=K('<div class="rounded-md bg-red-50 dark:bg-red-900 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path></svg></div> <div class="ml-3"><p class="text-sm font-medium text-red-800 dark:text-red-200"> </p></div></div></div>'),he=K('<div class="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 py-12 px-4 sm:px-6 lg:px-8"><div class="max-w-md w-full space-y-8"><div><div class="mx-auto h-48 w-auto flex justify-center"><img alt="GARM" class="h-48 w-auto dark:hidden"/> <img alt="GARM" class="h-48 w-auto hidden dark:block"/></div> <h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">Sign in to GARM</h2> <p class="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">GitHub Actions Runner Manager</p></div> <form class="mt-8 space-y-6"><div class="rounded-md shadow-sm -space-y-px"><div><label for="username" class="sr-only">Username</label> <input id="username" name="username" type="text" required class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-700 rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" placeholder="Username"/></div> <div><label for="password" class="sr-only">Password</label> <input id="password" name="password" type="password" required class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-700 rounded-b-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" placeholder="Password"/></div></div> <!> <div><!></div></form></div></div>');function Ae(W,F){ee(F,!1);const[J,N]=ne(),$=()=>ce(pe,"$authStore",J);let m=f(""),u=f(""),o=f(!1),n=f("");ae(()=>{O()});function O(){const e=localStorage.getItem("theme");let s=!1;e==="dark"?s=!0:e==="light"?s=!1:s=window.matchMedia("(prefers-color-scheme: dark)").matches,s?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")}async function M(){if(!a(m)||!a(u)){i(n,"Please enter both username and password");return}i(o,!0),i(n,"");try{await ve.login(a(m),a(u)),H(l("/"))}catch(e){i(n,fe(e))}finally{i(o,!1)}}function L(e){e.key==="Enter"&&M()}re(()=>($(),l),()=>{$().isAuthenticated&&H(l("/"))}),te(),Z();var g=he();se(e=>{oe.title="Login - GARM"});var z=r(g),h=r(z),A=r(h),S=r(A),Q=d(S,2);t(A),D(4),t(h);var b=d(h,2),x=r(b),y=r(x),p=d(r(y),2);U(p),t(y);var P=d(y,2),v=d(r(P),2);U(v),t(P),t(x);var G=d(x,2);{var V=e=>{var s=ge(),c=r(s),E=d(r(c),2),j=r(E),Y=r(j,!0);t(j),t(E),t(c),t(s),_(()=>I(Y,a(n))),w(e,s)};le(G,e=>{a(n)&&e(V)})}var R=d(G,2),X=r(R);me(X,{type:"submit",variant:"primary",size:"md",fullWidth:!0,get disabled(){return a(o)},get loading(){return a(o)},children:(e,s)=>{D();var c=ie();_(()=>I(c,a(o)?"Signing in...":"Sign in")),w(e,c)},$$slots:{default:!0}}),t(R),t(b),t(z),t(g),_((e,s)=>{T(S,"src",e),T(Q,"src",s),p.disabled=a(o),v.disabled=a(o)},[()=>(B(l),q(()=>l("/assets/garm-light.svg"))),()=>(B(l),q(()=>l("/assets/garm-dark.svg")))]),C(p,()=>a(m),e=>i(m,e)),k("keypress",p,L),C(v,()=>a(u),e=>i(u,e)),k("keypress",v,L),k("submit",b,ue(M)),w(W,g),de(),N()}export{Ae as component};
|
||||
import"../chunks/DsnmJJEf.js";import{i as Z}from"../chunks/TJn6xDN9.js";import{p as ee,o as ae,l as re,h as te,f as K,j as se,t as _,g as a,i as k,b as w,c as de,$ as oe,s as d,D as ie,m as f,d as r,u as q,q as B,k as i,r as t,z as D,e as I}from"../chunks/DniTuB_0.js";import{i as le,s as ne,a as ce}from"../chunks/DbNhg6mG.js";import{B as me,d as l,c as T,r as U}from"../chunks/DSfKzFV1.js";import{b as C}from"../chunks/CCQwxxp9.js";import{p as ue}from"../chunks/D4Caz1gY.js";import{g as H}from"../chunks/kW9-6GPQ.js";import{a as pe,b as ve}from"../chunks/Dt70yZzL.js";import{e as fe}from"../chunks/BZiHL9L3.js";var ge=K('<div class="rounded-md bg-red-50 dark:bg-red-900 p-4"><div class="flex"><div class="flex-shrink-0"><svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path></svg></div> <div class="ml-3"><p class="text-sm font-medium text-red-800 dark:text-red-200"> </p></div></div></div>'),he=K('<div class="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 py-12 px-4 sm:px-6 lg:px-8"><div class="max-w-md w-full space-y-8"><div><div class="mx-auto h-48 w-auto flex justify-center"><img alt="GARM" class="h-48 w-auto dark:hidden"/> <img alt="GARM" class="h-48 w-auto hidden dark:block"/></div> <h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">Sign in to GARM</h2> <p class="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">GitHub Actions Runner Manager</p></div> <form class="mt-8 space-y-6"><div class="rounded-md shadow-sm -space-y-px"><div><label for="username" class="sr-only">Username</label> <input id="username" name="username" type="text" required class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-700 rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" placeholder="Username"/></div> <div><label for="password" class="sr-only">Password</label> <input id="password" name="password" type="password" required class="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-600 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white bg-white dark:bg-gray-700 rounded-b-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm" placeholder="Password"/></div></div> <!> <div><!></div></form></div></div>');function Ae(W,F){ee(F,!1);const[J,N]=ne(),$=()=>ce(pe,"$authStore",J);let m=f(""),u=f(""),o=f(!1),n=f("");ae(()=>{O()});function O(){const e=localStorage.getItem("theme");let s=!1;e==="dark"?s=!0:e==="light"?s=!1:s=window.matchMedia("(prefers-color-scheme: dark)").matches,s?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")}async function M(){if(!a(m)||!a(u)){i(n,"Please enter both username and password");return}i(o,!0),i(n,"");try{await ve.login(a(m),a(u)),H(l("/"))}catch(e){i(n,fe(e))}finally{i(o,!1)}}function L(e){e.key==="Enter"&&M()}re(()=>($(),l),()=>{$().isAuthenticated&&H(l("/"))}),te(),Z();var g=he();se(e=>{oe.title="Login - GARM"});var z=r(g),h=r(z),A=r(h),S=r(A),Q=d(S,2);t(A),D(4),t(h);var b=d(h,2),x=r(b),y=r(x),p=d(r(y),2);U(p),t(y);var P=d(y,2),v=d(r(P),2);U(v),t(P),t(x);var G=d(x,2);{var V=e=>{var s=ge(),c=r(s),E=d(r(c),2),j=r(E),Y=r(j,!0);t(j),t(E),t(c),t(s),_(()=>I(Y,a(n))),w(e,s)};le(G,e=>{a(n)&&e(V)})}var R=d(G,2),X=r(R);me(X,{type:"submit",variant:"primary",size:"md",fullWidth:!0,get disabled(){return a(o)},get loading(){return a(o)},children:(e,s)=>{D();var c=ie();_(()=>I(c,a(o)?"Signing in...":"Sign in")),w(e,c)},$$slots:{default:!0}}),t(R),t(b),t(z),t(g),_((e,s)=>{T(S,"src",e),T(Q,"src",s),p.disabled=a(o),v.disabled=a(o)},[()=>(B(l),q(()=>l("/assets/garm-light.svg"))),()=>(B(l),q(()=>l("/assets/garm-dark.svg")))]),C(p,()=>a(m),e=>i(m,e)),k("keypress",p,L),C(v,()=>a(u),e=>i(u,e)),k("keypress",v,L),k("submit",b,ue(M)),w(W,g),de(),N()}export{Ae as component};
|
||||
7
webapp/assets/_app/immutable/nodes/11.B9eGfscp.js
Normal file
7
webapp/assets/_app/immutable/nodes/11.B9eGfscp.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/nodes/12.DEH2x_tr.js
Normal file
1
webapp/assets/_app/immutable/nodes/12.DEH2x_tr.js
Normal file
File diff suppressed because one or more lines are too long
1
webapp/assets/_app/immutable/nodes/13.NurrRkua.js
Normal file
1
webapp/assets/_app/immutable/nodes/13.NurrRkua.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
webapp/assets/_app/immutable/nodes/22.HPy9RpzE.js
Normal file
2
webapp/assets/_app/immutable/nodes/22.HPy9RpzE.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
webapp/assets/_app/immutable/nodes/3.HdI83u8i.js
Normal file
7
webapp/assets/_app/immutable/nodes/3.HdI83u8i.js
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue