mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-19 12:55:15 +00:00
Merge branch 'main' into fix/login-org-assign
This commit is contained in:
commit
a62832a01d
28 changed files with 444 additions and 214 deletions
|
@ -202,6 +202,7 @@
|
|||
"typecheck",
|
||||
"Typeflag",
|
||||
"unplugin",
|
||||
"unsanitize",
|
||||
"Upsert",
|
||||
"urfave",
|
||||
"usecase",
|
||||
|
|
|
@ -4306,7 +4306,7 @@ const docTemplate = `{
|
|||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Repo"
|
||||
"$ref": "#/definitions/RepoLastPipeline"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5132,6 +5132,99 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"RepoLastPipeline": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_deploy": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"allow_pr": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"approval_allowed_users": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"cancel_previous_pipeline_events": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/WebhookEvent"
|
||||
}
|
||||
},
|
||||
"clone_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"clone_url_ssh": {
|
||||
"type": "string"
|
||||
},
|
||||
"config_file": {
|
||||
"type": "string"
|
||||
},
|
||||
"default_branch": {
|
||||
"type": "string"
|
||||
},
|
||||
"forge_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"forge_remote_id": {
|
||||
"description": "ForgeRemoteID is the unique identifier for the repository on the forge.",
|
||||
"type": "string"
|
||||
},
|
||||
"forge_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"full_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"last_pipeline": {
|
||||
"$ref": "#/definitions/Pipeline"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"netrc_trusted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"org_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
},
|
||||
"pr_enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"private": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"require_approval": {
|
||||
"$ref": "#/definitions/model.ApprovalMode"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "integer"
|
||||
},
|
||||
"trusted": {
|
||||
"$ref": "#/definitions/model.TrustedConfiguration"
|
||||
},
|
||||
"visibility": {
|
||||
"$ref": "#/definitions/RepoVisibility"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RepoPatch": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -26,9 +26,9 @@ If you experience bugs, please check which component has the issue. If it's the
|
|||
|
||||
## List of addon forges
|
||||
|
||||
If you wrote or found an addon forge, please add it here so others can find it!
|
||||
### Radicle Forge
|
||||
|
||||
_Be the first one to add your addon forge!_
|
||||
[Radicle](https://radicle.xyz/) is an open source, peer-to-peer code collaboration stack built on Git. Radicle addon for Woodpecker CI can be found at [this repo](https://explorer.radicle.gr/nodes/seed.radicle.gr/rad:z39Cf1XzrvCLRZZJRUZnx9D1fj5ws).
|
||||
|
||||
## Creating addon forges
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ If you experience bugs, please check which component has the issue. If it's the
|
|||
|
||||
## List of addon forges
|
||||
|
||||
If you wrote or found an addon forge, please add it here so others can find it!
|
||||
### Radicle Forge
|
||||
|
||||
_Be the first one to add your addon forge!_
|
||||
[Radicle](https://radicle.xyz/) is an open source, peer-to-peer code collaboration stack built on Git. Radicle addon for Woodpecker CI can be found at [this repo](https://explorer.radicle.gr/nodes/seed.radicle.gr/rad:z39Cf1XzrvCLRZZJRUZnx9D1fj5ws).
|
||||
|
||||
## Creating addon forges
|
||||
|
||||
|
|
8
go.mod
8
go.mod
|
@ -11,7 +11,7 @@ require (
|
|||
github.com/6543/logfile-open v1.2.1
|
||||
github.com/adrg/xdg v0.5.3
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
||||
github.com/cenkalti/backoff/v5 v5.0.1
|
||||
github.com/cenkalti/backoff/v5 v5.0.2
|
||||
github.com/charmbracelet/huh v0.6.0
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10
|
||||
github.com/distribution/reference v0.6.0
|
||||
|
@ -58,14 +58,14 @@ require (
|
|||
github.com/zalando/go-keyring v0.2.6
|
||||
gitlab.com/gitlab-org/api/client-go v0.122.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/oauth2 v0.26.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/term v0.29.0
|
||||
golang.org/x/text v0.22.0
|
||||
google.golang.org/grpc v1.70.0
|
||||
google.golang.org/protobuf v1.36.4
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.32.1
|
||||
k8s.io/apimachinery v0.32.1
|
||||
|
|
16
go.sum
16
go.sum
|
@ -52,8 +52,8 @@ github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
|
|||
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.1 h1:kGZdCHH1+eW+Yd0wftimjMuhg9zidDvNF5aGdnkkb+U=
|
||||
github.com/cenkalti/backoff/v5 v5.0.1/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
||||
|
@ -607,8 +607,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
|
@ -631,8 +631,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
|
||||
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -730,8 +730,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
|||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.1
|
||||
// protoc v5.28.3
|
||||
// protoc-gen-go v1.36.4
|
||||
// protoc v5.29.3
|
||||
// source: woodpecker.proto
|
||||
|
||||
package proto
|
||||
|
@ -26,6 +26,7 @@ import (
|
|||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -1145,7 +1146,7 @@ func (x *AuthResponse) GetAccessToken() string {
|
|||
|
||||
var File_woodpecker_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_woodpecker_proto_rawDesc = []byte{
|
||||
var file_woodpecker_proto_rawDesc = string([]byte{
|
||||
0x0a, 0x10, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x53, 0x74,
|
||||
0x65, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x5f,
|
||||
|
@ -1299,19 +1300,19 @@ var file_woodpecker_proto_rawDesc = []byte{
|
|||
0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x6f, 0x2e, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63,
|
||||
0x6b, 0x65, 0x72, 0x2d, 0x63, 0x69, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x77, 0x6f, 0x6f, 0x64, 0x70,
|
||||
0x65, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e,
|
||||
0x65, 0x63, 0x6b, 0x65, 0x72, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e,
|
||||
0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
}
|
||||
})
|
||||
|
||||
var (
|
||||
file_woodpecker_proto_rawDescOnce sync.Once
|
||||
file_woodpecker_proto_rawDescData = file_woodpecker_proto_rawDesc
|
||||
file_woodpecker_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_woodpecker_proto_rawDescGZIP() []byte {
|
||||
file_woodpecker_proto_rawDescOnce.Do(func() {
|
||||
file_woodpecker_proto_rawDescData = protoimpl.X.CompressGZIP(file_woodpecker_proto_rawDescData)
|
||||
file_woodpecker_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_woodpecker_proto_rawDesc), len(file_woodpecker_proto_rawDesc)))
|
||||
})
|
||||
return file_woodpecker_proto_rawDescData
|
||||
}
|
||||
|
@ -1392,7 +1393,7 @@ func file_woodpecker_proto_init() {
|
|||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_woodpecker_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_woodpecker_proto_rawDesc), len(file_woodpecker_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 23,
|
||||
NumExtensions: 0,
|
||||
|
@ -1403,7 +1404,6 @@ func file_woodpecker_proto_init() {
|
|||
MessageInfos: file_woodpecker_proto_msgTypes,
|
||||
}.Build()
|
||||
File_woodpecker_proto = out.File
|
||||
file_woodpecker_proto_rawDesc = nil
|
||||
file_woodpecker_proto_goTypes = nil
|
||||
file_woodpecker_proto_depIdxs = nil
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.28.3
|
||||
// - protoc v5.29.3
|
||||
// source: woodpecker.proto
|
||||
|
||||
package proto
|
||||
|
|
|
@ -120,6 +120,7 @@ func PostRepo(c *gin.Context) {
|
|||
|
||||
// find org of repo
|
||||
var org *model.Org
|
||||
// TODO: find org by name and forge id
|
||||
org, err = _store.OrgFindByName(repo.Owner)
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
c.String(http.StatusInternalServerError, err.Error())
|
||||
|
@ -148,19 +149,6 @@ func PostRepo(c *gin.Context) {
|
|||
|
||||
repo.OrgID = org.ID
|
||||
|
||||
if enabledOnce {
|
||||
err = _store.UpdateRepo(repo)
|
||||
} else {
|
||||
repo.ForgeID = user.ForgeID // TODO: allow to use other connected forges of the user
|
||||
err = _store.CreateRepo(repo)
|
||||
}
|
||||
if err != nil {
|
||||
msg := "could not create/update repo in store."
|
||||
log.Error().Err(err).Msg(msg)
|
||||
c.String(http.StatusInternalServerError, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// creates the jwt token used to verify the repository
|
||||
t := token.New(token.HookToken)
|
||||
t.Set("repo-id", strconv.FormatInt(repo.ID, 10))
|
||||
|
@ -186,6 +174,19 @@ func PostRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if enabledOnce {
|
||||
err = _store.UpdateRepo(repo)
|
||||
} else {
|
||||
repo.ForgeID = user.ForgeID // TODO: allow to use other connected forges of the user
|
||||
err = _store.CreateRepo(repo)
|
||||
}
|
||||
if err != nil {
|
||||
msg := "could not create/update repo in store."
|
||||
log.Error().Err(err).Msg(msg)
|
||||
c.String(http.StatusInternalServerError, msg)
|
||||
return
|
||||
}
|
||||
|
||||
repo.Perm = from.Perm
|
||||
repo.Perm.Synced = time.Now().Unix()
|
||||
repo.Perm.UserID = user.ID
|
||||
|
@ -455,10 +456,7 @@ func DeleteRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
repo.IsActive = false
|
||||
repo.UserID = 0
|
||||
|
||||
if err := _store.UpdateRepo(repo); err != nil {
|
||||
if err := _forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -468,12 +466,16 @@ func DeleteRepo(c *gin.Context) {
|
|||
handleDBError(c, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
repo.IsActive = false
|
||||
repo.UserID = 0
|
||||
|
||||
if err := _store.UpdateRepo(repo); err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := _forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, repo)
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ func GetFeed(c *gin.Context) {
|
|||
// @Description Retrieve the currently authenticated User's Repository list
|
||||
// @Router /user/repos [get]
|
||||
// @Produce json
|
||||
// @Success 200 {array} Repo
|
||||
// @Success 200 {array} RepoLastPipeline
|
||||
// @Tags User
|
||||
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
|
||||
// @Param all query bool false "query all repos, including inactive ones"
|
||||
|
@ -140,7 +140,31 @@ func GetRepos(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, activeRepos)
|
||||
repoIDs := make([]int64, len(activeRepos))
|
||||
for i, repo := range activeRepos {
|
||||
repoIDs[i] = repo.ID
|
||||
}
|
||||
|
||||
pipelines, err := _store.GetRepoLatestPipelines(repoIDs)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Error fetching repository list. %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
latestPipelines := make(map[int64]*model.Pipeline, len(activeRepos))
|
||||
for _, pipeline := range pipelines {
|
||||
latestPipelines[pipeline.RepoID] = pipeline
|
||||
}
|
||||
|
||||
repos := make([]*model.RepoLastPipeline, len(activeRepos))
|
||||
for i, repo := range activeRepos {
|
||||
repos[i] = &model.RepoLastPipeline{
|
||||
Repo: repo,
|
||||
LastPipeline: latestPipelines[repo.ID],
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, repos)
|
||||
}
|
||||
|
||||
// PostToken
|
||||
|
|
|
@ -71,7 +71,7 @@ type Repo struct {
|
|||
Hash string `json:"-" xorm:"varchar(500) 'hash'"`
|
||||
Perm *Perm `json:"-" xorm:"-"`
|
||||
CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"`
|
||||
NetrcTrustedPlugins []string `json:"netrc_trusted" xorm:"json 'netrc_trusted'"`
|
||||
NetrcTrustedPlugins []string `json:"netrc_trusted" xorm:"json 'netrc_trusted'"`
|
||||
} // @name Repo
|
||||
|
||||
// TableName return database table name for xorm.
|
||||
|
@ -157,3 +157,9 @@ type TrustedConfigurationPatch struct {
|
|||
Volumes *bool `json:"volumes"`
|
||||
Security *bool `json:"security"`
|
||||
}
|
||||
|
||||
// RepoLastPipeline represents a repository with last pipeline execution information.
|
||||
type RepoLastPipeline struct {
|
||||
*Repo
|
||||
LastPipeline *Pipeline `json:"last_pipeline,omitempty"`
|
||||
} // @name RepoLastPipeline
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2025 Woodpecker Authors
|
||||
//
|
||||
// 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 migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
var unSanitizeOrgAndUserNames = xormigrate.Migration{
|
||||
ID: "unsanitize-org-and-user-names",
|
||||
MigrateSession: func(sess *xorm.Session) (err error) {
|
||||
type user struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
Login string `xorm:"TEXT 'login'"`
|
||||
ForgeID int64 `xorm:"forge_id"`
|
||||
}
|
||||
|
||||
type org struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
Name string `xorm:"TEXT 'name'"`
|
||||
ForgeID int64 `xorm:"forge_id"`
|
||||
}
|
||||
|
||||
if err := sess.Sync(new(user), new(org)); err != nil {
|
||||
return fmt.Errorf("sync new models failed: %w", err)
|
||||
}
|
||||
|
||||
// get all users
|
||||
var users []*user
|
||||
if err := sess.Find(&users); err != nil {
|
||||
return fmt.Errorf("find all repos failed: %w", err)
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
userOrg := &org{}
|
||||
_, err := sess.Where("name = ? AND forge_id = ?", user.Login, user.ForgeID).Get(userOrg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting org failed: %w", err)
|
||||
}
|
||||
|
||||
if user.Login != userOrg.Name {
|
||||
userOrg.Name = user.Login
|
||||
if _, err := sess.Where(builder.Eq{"id": userOrg.ID}).Cols("Name").Update(userOrg); err != nil {
|
||||
return fmt.Errorf("updating org name failed: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
|
@ -52,6 +52,7 @@ var migrationTasks = []*xormigrate.Migration{
|
|||
&renameTokenFields,
|
||||
&setNewDefaultsForRequireApproval,
|
||||
&removeRepoScm,
|
||||
&unSanitizeOrgAndUserNames,
|
||||
}
|
||||
|
||||
var allBeans = []any{
|
||||
|
|
|
@ -16,7 +16,6 @@ package datastore
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
|
@ -28,8 +27,6 @@ func (s storage) OrgCreate(org *model.Org) error {
|
|||
}
|
||||
|
||||
func (s storage) orgCreate(org *model.Org, sess *xorm.Session) error {
|
||||
// sanitize
|
||||
org.Name = strings.ToLower(org.Name)
|
||||
if org.Name == "" {
|
||||
return fmt.Errorf("org name is empty")
|
||||
}
|
||||
|
@ -48,8 +45,6 @@ func (s storage) OrgUpdate(org *model.Org) error {
|
|||
}
|
||||
|
||||
func (s storage) orgUpdate(sess *xorm.Session, org *model.Org) error {
|
||||
// sanitize
|
||||
org.Name = strings.ToLower(org.Name)
|
||||
// update
|
||||
_, err := sess.ID(org.ID).AllCols().Update(org)
|
||||
return err
|
||||
|
@ -84,7 +79,6 @@ func (s storage) OrgFindByName(name string) (*model.Org, error) {
|
|||
|
||||
func (s storage) orgFindByName(sess *xorm.Session, name string) (*model.Org, error) {
|
||||
// sanitize
|
||||
name = strings.ToLower(name)
|
||||
org := new(model.Org)
|
||||
return org, wrapGet(sess.Where("name = ?", name).Get(org))
|
||||
}
|
||||
|
|
|
@ -34,7 +34,10 @@ func TestOrgCRUD(t *testing.T) {
|
|||
|
||||
// create first org to play with
|
||||
assert.NoError(t, store.OrgCreate(org1))
|
||||
assert.EqualValues(t, "someawesomeorg", org1.Name)
|
||||
assert.EqualValues(t, "someAwesomeOrg", org1.Name)
|
||||
|
||||
// don't allow the same name in different casing
|
||||
assert.Error(t, store.OrgCreate(&model.Org{ID: org1.ID, Name: "someawesomeorg"}))
|
||||
|
||||
// retrieve it
|
||||
orgOne, err := store.OrgGet(org1.ID)
|
||||
|
@ -44,17 +47,14 @@ func TestOrgCRUD(t *testing.T) {
|
|||
// change name
|
||||
assert.NoError(t, store.OrgUpdate(&model.Org{ID: org1.ID, Name: "RenamedOrg"}))
|
||||
|
||||
// force a name duplication and fail
|
||||
assert.Error(t, store.OrgCreate(&model.Org{Name: "reNamedorg"}))
|
||||
|
||||
// find updated org by name
|
||||
orgOne, err = store.OrgFindByName("renamedorG")
|
||||
orgOne, err = store.OrgFindByName("RenamedOrg")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqualValues(t, org1, orgOne)
|
||||
assert.EqualValues(t, org1.ID, orgOne.ID)
|
||||
assert.EqualValues(t, false, orgOne.IsUser)
|
||||
assert.EqualValues(t, false, orgOne.Private)
|
||||
assert.EqualValues(t, "renamedorg", orgOne.Name)
|
||||
assert.EqualValues(t, "RenamedOrg", orgOne.Name)
|
||||
|
||||
// create two more orgs and repos
|
||||
someUser := &model.Org{Name: "some_other_u", IsUser: true}
|
||||
|
|
|
@ -97,6 +97,22 @@ func (s storage) GetPipelineList(repo *model.Repo, p *model.ListOptions, f *mode
|
|||
Find(&pipelines)
|
||||
}
|
||||
|
||||
// GetRepoLatestPipelines get the latest pipeline for each repo.
|
||||
func (s storage) GetRepoLatestPipelines(repoIDs []int64) ([]*model.Pipeline, error) {
|
||||
pipelines := make([]*model.Pipeline, 0, len(repoIDs))
|
||||
|
||||
pipelineIDs := make([]int64, 0, len(repoIDs))
|
||||
if err := s.engine.Select("MAX(id) AS id").
|
||||
Table("pipelines").
|
||||
Where(builder.In("repo_id", repoIDs)).
|
||||
GroupBy("repo_id").
|
||||
Find(&pipelineIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pipelines, s.engine.Where(builder.In("id", pipelineIDs)).Find(&pipelines)
|
||||
}
|
||||
|
||||
// GetActivePipelineList get all pipelines that are pending, running or blocked.
|
||||
func (s storage) GetActivePipelineList(repo *model.Repo) ([]*model.Pipeline, error) {
|
||||
pipelines := make([]*model.Pipeline, 0)
|
||||
|
|
|
@ -110,14 +110,6 @@ func TestGetRepoName(t *testing.T) {
|
|||
assert.Equal(t, repo.UserID, getrepo.UserID)
|
||||
assert.Equal(t, repo.Owner, getrepo.Owner)
|
||||
assert.Equal(t, repo.Name, getrepo.Name)
|
||||
|
||||
// case-insensitive
|
||||
getrepo, err = store.GetRepoName("Bradrydzewski/test")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, repo.ID, getrepo.ID)
|
||||
assert.Equal(t, repo.UserID, getrepo.UserID)
|
||||
assert.Equal(t, repo.Owner, getrepo.Owner)
|
||||
assert.Equal(t, repo.Name, getrepo.Name)
|
||||
}
|
||||
|
||||
func TestRepoList(t *testing.T) {
|
||||
|
|
|
@ -61,8 +61,8 @@ func TestUsers(t *testing.T) {
|
|||
|
||||
// check unique login
|
||||
user2 := model.User{
|
||||
Login: "joe",
|
||||
Email: "foo@bar.com",
|
||||
Login: "Joe",
|
||||
Email: "foo2@bar.com",
|
||||
AccessToken: "ab20g0ddaf012c744e136da16aa21ad9",
|
||||
}
|
||||
err2 = store.CreateUser(&user2)
|
||||
|
@ -102,13 +102,13 @@ func TestCreateUserWithExistingOrg(t *testing.T) {
|
|||
existingOrg := &model.Org{
|
||||
ForgeID: 1,
|
||||
IsUser: true,
|
||||
Name: "existingorg",
|
||||
Name: "existingOrg",
|
||||
Private: false,
|
||||
}
|
||||
|
||||
err := store.OrgCreate(existingOrg)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "existingorg", existingOrg.Name)
|
||||
assert.EqualValues(t, "existingOrg", existingOrg.Name)
|
||||
|
||||
// Create a new user with the same name as the existing organization
|
||||
newUser := &model.User{
|
||||
|
@ -120,7 +120,7 @@ func TestCreateUserWithExistingOrg(t *testing.T) {
|
|||
|
||||
updatedOrg, err := store.OrgGet(existingOrg.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "existingorg", updatedOrg.Name)
|
||||
assert.Equal(t, "existingOrg", updatedOrg.Name)
|
||||
|
||||
newUser2 := &model.User{
|
||||
Login: "new-user",
|
||||
|
|
|
@ -1044,6 +1044,36 @@ func (_m *Store) GetRepoForgeID(_a0 model.ForgeRemoteID) (*model.Repo, error) {
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// GetRepoLatestPipelines provides a mock function with given fields: _a0
|
||||
func (_m *Store) GetRepoLatestPipelines(_a0 []int64) ([]*model.Pipeline, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRepoLatestPipelines")
|
||||
}
|
||||
|
||||
var r0 []*model.Pipeline
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([]int64) ([]*model.Pipeline, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([]int64) []*model.Pipeline); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Pipeline)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([]int64) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetRepoName provides a mock function with given fields: _a0
|
||||
func (_m *Store) GetRepoName(_a0 string) (*model.Repo, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
|
|
@ -80,6 +80,8 @@ type Store interface {
|
|||
GetPipelineLastBefore(*model.Repo, string, int64) (*model.Pipeline, error)
|
||||
// GetPipelineList gets a list of pipelines for the repository
|
||||
GetPipelineList(*model.Repo, *model.ListOptions, *model.PipelineFilter) ([]*model.Pipeline, error)
|
||||
// GetRepoLatestPipelines gets the latest pipelines for the given repo IDs.
|
||||
GetRepoLatestPipelines([]int64) ([]*model.Pipeline, error)
|
||||
// GetActivePipelineList gets a list of the active pipelines for the repository
|
||||
GetActivePipelineList(repo *model.Repo) ([]*model.Pipeline, error)
|
||||
// GetPipelineQueue gets a list of pipelines in queue.
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
"dependencies": {
|
||||
"@kyvg/vue3-notification": "^3.4.1",
|
||||
"@mdi/js": "^7.4.47",
|
||||
"@tailwindcss/postcss": "4.0.4",
|
||||
"@tailwindcss/postcss": "4.0.5",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/vite": "4.0.4",
|
||||
"@tailwindcss/vite": "4.0.5",
|
||||
"@vueuse/core": "^12.3.0",
|
||||
"ansi_up": "^6.0.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
|
|
|
@ -18,14 +18,14 @@ importers:
|
|||
specifier: ^7.4.47
|
||||
version: 7.4.47
|
||||
'@tailwindcss/postcss':
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4
|
||||
specifier: 4.0.5
|
||||
version: 4.0.5
|
||||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.13.1)(typescript@5.7.3)))
|
||||
'@tailwindcss/vite':
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(stylus@0.57.0)(yaml@2.7.0))
|
||||
specifier: 4.0.5
|
||||
version: 4.0.5(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(stylus@0.57.0)(yaml@2.7.0))
|
||||
'@vueuse/core':
|
||||
specifier: ^12.3.0
|
||||
version: 12.5.0(typescript@5.7.3)
|
||||
|
@ -61,7 +61,7 @@ importers:
|
|||
version: 8.5.1
|
||||
prettier-plugin-tailwindcss:
|
||||
specifier: ^0.6.9
|
||||
version: 0.6.11(@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.4.2))(prettier@3.4.2)
|
||||
version: 0.6.11(@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.0))(prettier@3.5.0)
|
||||
prismjs:
|
||||
specifier: ^1.29.0
|
||||
version: 1.29.0
|
||||
|
@ -70,7 +70,7 @@ importers:
|
|||
version: 7.7.1
|
||||
simple-icons:
|
||||
specifier: ^14.1.0
|
||||
version: 14.5.0
|
||||
version: 14.6.0
|
||||
tailwindcss:
|
||||
specifier: ^3.4.17
|
||||
version: 3.4.17(ts-node@10.9.2(@types/node@22.13.1)(typescript@5.7.3))
|
||||
|
@ -79,7 +79,7 @@ importers:
|
|||
version: 3.5.13(typescript@5.7.3)
|
||||
vue-i18n:
|
||||
specifier: ^11.0.1
|
||||
version: 11.1.0(vue@3.5.13(typescript@5.7.3))
|
||||
version: 11.1.1(vue@3.5.13(typescript@5.7.3))
|
||||
vue-router:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0(vue@3.5.13(typescript@5.7.3))
|
||||
|
@ -92,13 +92,13 @@ importers:
|
|||
version: 9.20.0
|
||||
'@ianvs/prettier-plugin-sort-imports':
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.4.2)
|
||||
version: 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.0)
|
||||
'@intlify/eslint-plugin-vue-i18n':
|
||||
specifier: 3.2.0
|
||||
version: 3.2.0(eslint@9.20.0(jiti@2.4.2))
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.0(jiti@2.4.2))(rollup@4.34.6)(typescript@5.7.3)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
version: 6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.0(jiti@2.4.2))(rollup@4.34.6)(typescript@5.7.3)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@types/eslint__js':
|
||||
specifier: ^8.42.3
|
||||
version: 8.42.3
|
||||
|
@ -140,7 +140,7 @@ importers:
|
|||
version: 26.0.0
|
||||
prettier:
|
||||
specifier: ^3.4.2
|
||||
version: 3.4.2
|
||||
version: 3.5.0
|
||||
tinycolor2:
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0
|
||||
|
@ -589,8 +589,8 @@ packages:
|
|||
vue-i18n:
|
||||
optional: true
|
||||
|
||||
'@intlify/core-base@11.1.0':
|
||||
resolution: {integrity: sha512-5KFrnfgcv4cVWzA1RC4HqMHYEWSD/69GQU7wpKJ2l6mA6ggqEjb9NJN5VJNJvP2mU5y8MAGwXLAJXJo5sbIkMQ==}
|
||||
'@intlify/core-base@11.1.1':
|
||||
resolution: {integrity: sha512-bb8gZvoeKExCI2r/NVCK9E4YyOkvYGaSCPxVZe8T0jz8aX+dHEOZWxK06Z/Y9mWRkJfBiCH4aOhDF1yr1t5J8Q==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/core-base@9.14.2':
|
||||
|
@ -607,8 +607,8 @@ packages:
|
|||
resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.1.0':
|
||||
resolution: {integrity: sha512-UuV1YwWPBNgL4uqtC1vZPHF2QtYYqVeCDIsbV6JC6Vv90UWmEiU77U7EZmNVVV7DepT83Ow5MaF1CiWI77b61w==}
|
||||
'@intlify/message-compiler@11.1.1':
|
||||
resolution: {integrity: sha512-4iEsUZ3aF7jXY19CJFN5VP+pPyLITD9FVsjB13z9TU1UxaZLlFsmNhvRxlPDSOfHAP5RpNF2QKKdZ3DHVf4Yzw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@9.14.2':
|
||||
|
@ -619,8 +619,8 @@ packages:
|
|||
resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.1.0':
|
||||
resolution: {integrity: sha512-DvpNSxiMrFqYMaGSRDDnQgO/L0MqNH4KWw9CUx8LRHHIdWp08En9DpmSRNpauUOxKpHAhyJJxx92BHZk9J84EQ==}
|
||||
'@intlify/shared@11.1.1':
|
||||
resolution: {integrity: sha512-2kGiWoXaeV8HZlhU/Nml12oTbhv7j2ufsJ5vQaa0VTjzUmZVdd/nmKFRAOJ/FtjO90Qba5AnZDwsrY7ZND5udA==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@9.14.2':
|
||||
|
@ -828,89 +828,89 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: '>=8.40.0'
|
||||
|
||||
'@tailwindcss/node@4.0.4':
|
||||
resolution: {integrity: sha512-VLFq80IyoV1hsHPcCm1mmlyPyUT6NlovQLoO2y7PGm84mW94ZrNJ7ax5H6K4M7Aj/fdMfem5IX7Ka+LXWZpDGg==}
|
||||
'@tailwindcss/node@4.0.5':
|
||||
resolution: {integrity: sha512-ffTz4DX1cgr4XPuqjhm32YV6Lyx58R1CxAAnSFTamg6wXwfk3oWdb6exgAbGesPzvUgicTO0gwUdQGSsg4nNog==}
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.0.4':
|
||||
resolution: {integrity: sha512-hiGUA8d15ynH/LdurQNObnuTjri7i4ApAzhesusNxoz4br7vhZ6QO5CFgniYAYNZvf8Q8wCTBg0nj61RalBeVQ==}
|
||||
'@tailwindcss/oxide-android-arm64@4.0.5':
|
||||
resolution: {integrity: sha512-kK/ik8aIAKWDIEYDZGUCJcnU1qU5sPoMBlVzPvtsUqiV6cSHcnVRUdkcLwKqTeUowzZtjjRiamELLd9Gb0x5BQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.0.4':
|
||||
resolution: {integrity: sha512-vTca+ysNl8BYmYJTni9pLC+L3S4bvrj0ai1eUV3yYXYa5Cpugr5Fni6ylV0gcTZOyETm2RCCJ/0azU6MgqE6HA==}
|
||||
'@tailwindcss/oxide-darwin-arm64@4.0.5':
|
||||
resolution: {integrity: sha512-vkbXFv0FfAEbrSa5NBjFEE+xi06ha7mxuxjY8LRn7d7/tBGrAZOEJnnsEbB6M1+x2pGRTjjei0XyTIXdVCglJA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.0.4':
|
||||
resolution: {integrity: sha512-rxPWb5AQJ/aAM/5UDCjaQaMYIcrZHe/Dr9xZu9+P9nJf3WAweNsGi+e+SW9EYGRiF3hkBtP2dvxVNAkTiEbNQQ==}
|
||||
'@tailwindcss/oxide-darwin-x64@4.0.5':
|
||||
resolution: {integrity: sha512-PedA64rHBXEa4e6abBWE4Yj4gHulfPb5T+rBNnX+WGkjjge5Txa2oS99TLmJ5BPDkXXqz/Ba7oweWIDDG7i5NQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.0.4':
|
||||
resolution: {integrity: sha512-UOnRHzlS5V5cxaMgBo6rk1E92tTDUtO/falc9vOpNiRdWhNcofYNN9zvZP63Wuo5FC6/XCyAnJo6OXUm18TwrQ==}
|
||||
'@tailwindcss/oxide-freebsd-x64@4.0.5':
|
||||
resolution: {integrity: sha512-silz3nuZdEYDfic3v/ooVUQChj9hbxDSee43GCQNwr/iD9L4K/JsZtoNqr0w69pUkvWcKINOGOG0r7WqUqkAeg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.0.4':
|
||||
resolution: {integrity: sha512-0Ry9Qfnf22rmJwHxsCFmHQIl5RZw+yOUUGHaqNT42REL8r308cU/bi4UqdrjqVRfAlu51gOGxTRf2NRueczuIA==}
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.0.5':
|
||||
resolution: {integrity: sha512-ElneG75XS64B9I2G83A/Hc7EtNVOD5xahs7avq0aeW7mEX6CtMc8m8RCXMn3jGhz8enFE52l6QU0wO7iVkEtXQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.0.4':
|
||||
resolution: {integrity: sha512-5a7WD30nVdI7Rl1ohZ0Ojj9t5yRnZkJBizvh3uIW52h9UeNpon8TfoknF6rU/TwD32dQ0Cjo5CcCHtQ2wW9PCA==}
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.0.5':
|
||||
resolution: {integrity: sha512-8yoXpWTeIFaByUaKy2qRAppznLVaDHP9xYCAbS3FG7+uUwHi8CHE4TcomM7eyamo0U7dbUIDgKMGoAX5s2iVrA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.0.4':
|
||||
resolution: {integrity: sha512-m6s5jKSqos07l6NtHFd49Ljcaw4jIWHE7jq6eNPNz9SCzQqRzs4esP1t7jH8UljQ7JffKOl7yZPwK5Nf+irliw==}
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.0.5':
|
||||
resolution: {integrity: sha512-BDlVSiiJ08GRz9KKnXgaPFs2fkukPF3pym6uK3oWEKW45jKlVGgybLqulcV5nLEqREOuyq4Rn4vnZss4/bbQ/g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.0.4':
|
||||
resolution: {integrity: sha512-K5dBjGHzby9eyUBwy9YHFhKY+5i8fzIBZM1NBWp6L2xpM7OzW9WJDgNcgESkZami9g+EozkQLt3ZmMZHAieXkw==}
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.0.5':
|
||||
resolution: {integrity: sha512-DYgieNDRkTy69bWPgdsc47nAXa74P63P/RetUwYM9vYj5USyOfHCEcqIthkCuYw3dXKBhjgwe697TmL2g2jpAw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.0.4':
|
||||
resolution: {integrity: sha512-J8sskt+fA5ooq+kxy0Tf4E2TRWZD9Y8j3K+pnBwp9zdilLmSd8OHrB3e0/rO78KveZ6BE9ae75cKOWrT6wONmw==}
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.0.5':
|
||||
resolution: {integrity: sha512-z2RzUvOQl0ZqrZqmCFP53tJbBXQ3UmLD/E6J7+q0e+4VaFnXCcIYTfQbHgI8f3fash+q6gK80Ko/ywEQ+bvv6Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.0.4':
|
||||
resolution: {integrity: sha512-flFaaMc77NQbz0Fq73wBs9EH2lX1Oc2Z/3JuxoewpnGHpAGJ/j05tvBNMyTaGrKcHvf/+dk+mCDxb6+PmzGgnQ==}
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.0.5':
|
||||
resolution: {integrity: sha512-ho1dJ4o5Q8nAOxdMkbfBu5aSqI+/bzQ0jEeHcXaEdEJzf2fSWs3HY7bIKtE6vQS8c4SmSBvls7IhGPuJxNg+2Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.0.4':
|
||||
resolution: {integrity: sha512-WzMA0aL/24/JyNrv2Yhr/Og24QGRPWJMjRyCJ4HRoGMs6/8svOQKrnnZ/9LUFwn56irAndFBjWWnlaqykH+g5Q==}
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.0.5':
|
||||
resolution: {integrity: sha512-yjw6JhtyDXr+G0aZrj3L3NlEV7CobSqOdPyfo6G3d91WEZ5b8PyGm86IAreX08Jp9DChGXEd53gWysVpWCTs+w==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tailwindcss/oxide@4.0.4':
|
||||
resolution: {integrity: sha512-vPpu30KFLiGyPOoElkYt8WRvzGKVrrOz49KpfiGGtnQGmyUpL8VCbJzzEEcpKT5BpaaQidhFok+OXscf6hHjOQ==}
|
||||
'@tailwindcss/oxide@4.0.5':
|
||||
resolution: {integrity: sha512-iWGyOCu0TuzvCBisWbGv2K9+7QCfE0ztgtrZOvb9iF7V7ChVkD15Obe3HevZrhjngAc34jDA+OMSuSvkrpTy4A==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@tailwindcss/postcss@4.0.4':
|
||||
resolution: {integrity: sha512-Up8fB+DUhy8qvDqlHgZAWaL5iVEbypcuOjzlW4K6EyU+aGEvXK0/wrcKBKOTvg3KKP5givJMexJ0aG1hDPOuRg==}
|
||||
'@tailwindcss/postcss@4.0.5':
|
||||
resolution: {integrity: sha512-U7IPb+KMASETtUvISwePM+1h+jLQspXf2ncfX/LmP/4AaH7b7DJQhqXzDCaJQd/MIh54dRUO93i9q4+Xm7dlVg==}
|
||||
|
||||
'@tailwindcss/typography@0.5.16':
|
||||
resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||
|
||||
'@tailwindcss/vite@4.0.4':
|
||||
resolution: {integrity: sha512-zrWGbluPeXeoetUQoDFmt1dQIeiOBThfznla7zPIqST69rMmiDD4SZwJrHVoL5CvXz06AYQXz/M/jELSakL7Rg==}
|
||||
'@tailwindcss/vite@4.0.5':
|
||||
resolution: {integrity: sha512-/i4hjLTUYVjUG0MTUviQP3HR/hzwyzv8Sq4sz2pnsNuf+FIjjhJB0vcnIMH1KIX0k8ozD6CBv2Dl76tlm/JFFA==}
|
||||
peerDependencies:
|
||||
vite: ^5.2.0 || ^6
|
||||
|
||||
|
@ -2636,8 +2636,8 @@ packages:
|
|||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
|
||||
prettier@3.4.2:
|
||||
resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==}
|
||||
prettier@3.5.0:
|
||||
resolution: {integrity: sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
|
@ -2754,8 +2754,8 @@ packages:
|
|||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
simple-icons@14.5.0:
|
||||
resolution: {integrity: sha512-Jn68BKShJ1KHV28ayiV4PCLZV2XK0xVfT6i3AtW6PuMT3S9jILezgOQXCOKj4Y9GasjZYqHbkSvOHCePCVxfyA==}
|
||||
simple-icons@14.6.0:
|
||||
resolution: {integrity: sha512-s2C9qwZJpM2gkDpCeVxlN5/XpvCTM444pPX9JvLWRiFL7npZIjQISHR7EYUe7IgGEFyznmoRmM8VdJm5LQih+g==}
|
||||
engines: {node: '>=0.12.18'}
|
||||
|
||||
sisteransi@1.0.5:
|
||||
|
@ -2870,8 +2870,8 @@ packages:
|
|||
engines: {node: '>=14.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tailwindcss@4.0.4:
|
||||
resolution: {integrity: sha512-/ezDLEkOLf1lXkr9F2iI5BHJbexJpty5zkV2B8bGHCqAdbc9vk85Jgdkq+ZOvNkNPa3yAaqJ8DjRt584Bc84kw==}
|
||||
tailwindcss@4.0.5:
|
||||
resolution: {integrity: sha512-DZZIKX3tA23LGTjHdnwlJOTxfICD1cPeykLLsYF1RQBI9QsCR3i0szohJfJDVjr6aNRAIio5WVO7FGB77fRHwg==}
|
||||
|
||||
tapable@2.2.1:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
|
@ -3124,8 +3124,8 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: '>=6.0.0'
|
||||
|
||||
vue-i18n@11.1.0:
|
||||
resolution: {integrity: sha512-UgtYUe99mLfo7ya5TJSsJcgJZaqIunwXjff5UA03xRry0VtgN4zIUbuoycK9/ZZQJg5Cmr6V6zq+u0H0P0hlNw==}
|
||||
vue-i18n@11.1.1:
|
||||
resolution: {integrity: sha512-0P6DkKy96R4Wh2sIZJEHw8ivnlD1pnB6Ib/eldoF1SUpQutfKZv6aMqZwICS1gW0rwq24ZSXw7y3jW+PRVYqWA==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
@ -3629,20 +3629,20 @@ snapshots:
|
|||
|
||||
'@humanwhocodes/retry@0.4.1': {}
|
||||
|
||||
'@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.4.2)':
|
||||
'@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.0)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.26.5
|
||||
'@babel/parser': 7.26.7
|
||||
'@babel/traverse': 7.26.7
|
||||
'@babel/types': 7.26.7
|
||||
prettier: 3.4.2
|
||||
prettier: 3.5.0
|
||||
semver: 7.7.1
|
||||
optionalDependencies:
|
||||
'@vue/compiler-sfc': 3.5.13
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@intlify/bundle-utils@10.0.0(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))':
|
||||
'@intlify/bundle-utils@10.0.0(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.0.0-rc.1
|
||||
'@intlify/shared': 11.0.0-rc.1
|
||||
|
@ -3654,12 +3654,12 @@ snapshots:
|
|||
source-map-js: 1.2.1
|
||||
yaml-eslint-parser: 1.2.3
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.1.0(vue@3.5.13(typescript@5.7.3))
|
||||
vue-i18n: 11.1.1(vue@3.5.13(typescript@5.7.3))
|
||||
|
||||
'@intlify/core-base@11.1.0':
|
||||
'@intlify/core-base@11.1.1':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.1.0
|
||||
'@intlify/shared': 11.1.0
|
||||
'@intlify/message-compiler': 11.1.1
|
||||
'@intlify/shared': 11.1.1
|
||||
|
||||
'@intlify/core-base@9.14.2':
|
||||
dependencies:
|
||||
|
@ -3696,9 +3696,9 @@ snapshots:
|
|||
'@intlify/shared': 11.0.0-rc.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/message-compiler@11.1.0':
|
||||
'@intlify/message-compiler@11.1.1':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.1.0
|
||||
'@intlify/shared': 11.1.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/message-compiler@9.14.2':
|
||||
|
@ -3708,16 +3708,16 @@ snapshots:
|
|||
|
||||
'@intlify/shared@11.0.0-rc.1': {}
|
||||
|
||||
'@intlify/shared@11.1.0': {}
|
||||
'@intlify/shared@11.1.1': {}
|
||||
|
||||
'@intlify/shared@9.14.2': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.0(jiti@2.4.2))(rollup@4.34.6)(typescript@5.7.3)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.20.0(jiti@2.4.2))(rollup@4.34.6)(typescript@5.7.3)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.20.0(jiti@2.4.2))
|
||||
'@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))
|
||||
'@intlify/shared': 11.1.0
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@intlify/bundle-utils': 10.0.0(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))
|
||||
'@intlify/shared': 11.1.1
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.6)
|
||||
'@typescript-eslint/scope-manager': 8.22.0
|
||||
'@typescript-eslint/typescript-estree': 8.22.0(typescript@5.7.3)
|
||||
|
@ -3731,7 +3731,7 @@ snapshots:
|
|||
unplugin: 1.16.1
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.1.0(vue@3.5.13(typescript@5.7.3))
|
||||
vue-i18n: 11.1.1(vue@3.5.13(typescript@5.7.3))
|
||||
transitivePeerDependencies:
|
||||
- '@vue/compiler-dom'
|
||||
- eslint
|
||||
|
@ -3739,14 +3739,14 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.0)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.7
|
||||
optionalDependencies:
|
||||
'@intlify/shared': 11.1.0
|
||||
'@intlify/shared': 11.1.1
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
vue-i18n: 11.1.0(vue@3.5.13(typescript@5.7.3))
|
||||
vue-i18n: 11.1.1(vue@3.5.13(typescript@5.7.3))
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
|
@ -3883,67 +3883,67 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@tailwindcss/node@4.0.4':
|
||||
'@tailwindcss/node@4.0.5':
|
||||
dependencies:
|
||||
enhanced-resolve: 5.18.0
|
||||
jiti: 2.4.2
|
||||
tailwindcss: 4.0.4
|
||||
tailwindcss: 4.0.5
|
||||
|
||||
'@tailwindcss/oxide-android-arm64@4.0.4':
|
||||
'@tailwindcss/oxide-android-arm64@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-arm64@4.0.4':
|
||||
'@tailwindcss/oxide-darwin-arm64@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-darwin-x64@4.0.4':
|
||||
'@tailwindcss/oxide-darwin-x64@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-freebsd-x64@4.0.4':
|
||||
'@tailwindcss/oxide-freebsd-x64@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.0.4':
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.0.4':
|
||||
'@tailwindcss/oxide-linux-arm64-gnu@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.0.4':
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.0.4':
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.0.4':
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.0.4':
|
||||
'@tailwindcss/oxide-win32-arm64-msvc@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.0.4':
|
||||
'@tailwindcss/oxide-win32-x64-msvc@4.0.5':
|
||||
optional: true
|
||||
|
||||
'@tailwindcss/oxide@4.0.4':
|
||||
'@tailwindcss/oxide@4.0.5':
|
||||
optionalDependencies:
|
||||
'@tailwindcss/oxide-android-arm64': 4.0.4
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.0.4
|
||||
'@tailwindcss/oxide-darwin-x64': 4.0.4
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.0.4
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.4
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.0.4
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.0.4
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.0.4
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.0.4
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.0.4
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.0.4
|
||||
'@tailwindcss/oxide-android-arm64': 4.0.5
|
||||
'@tailwindcss/oxide-darwin-arm64': 4.0.5
|
||||
'@tailwindcss/oxide-darwin-x64': 4.0.5
|
||||
'@tailwindcss/oxide-freebsd-x64': 4.0.5
|
||||
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.5
|
||||
'@tailwindcss/oxide-linux-arm64-gnu': 4.0.5
|
||||
'@tailwindcss/oxide-linux-arm64-musl': 4.0.5
|
||||
'@tailwindcss/oxide-linux-x64-gnu': 4.0.5
|
||||
'@tailwindcss/oxide-linux-x64-musl': 4.0.5
|
||||
'@tailwindcss/oxide-win32-arm64-msvc': 4.0.5
|
||||
'@tailwindcss/oxide-win32-x64-msvc': 4.0.5
|
||||
|
||||
'@tailwindcss/postcss@4.0.4':
|
||||
'@tailwindcss/postcss@4.0.5':
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
'@tailwindcss/node': 4.0.4
|
||||
'@tailwindcss/oxide': 4.0.4
|
||||
'@tailwindcss/node': 4.0.5
|
||||
'@tailwindcss/oxide': 4.0.5
|
||||
lightningcss: 1.29.1
|
||||
postcss: 8.5.1
|
||||
tailwindcss: 4.0.4
|
||||
tailwindcss: 4.0.5
|
||||
|
||||
'@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.13.1)(typescript@5.7.3)))':
|
||||
dependencies:
|
||||
|
@ -3953,12 +3953,12 @@ snapshots:
|
|||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.13.1)(typescript@5.7.3))
|
||||
|
||||
'@tailwindcss/vite@4.0.4(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(stylus@0.57.0)(yaml@2.7.0))':
|
||||
'@tailwindcss/vite@4.0.5(vite@6.1.0(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(stylus@0.57.0)(yaml@2.7.0))':
|
||||
dependencies:
|
||||
'@tailwindcss/node': 4.0.4
|
||||
'@tailwindcss/oxide': 4.0.4
|
||||
'@tailwindcss/node': 4.0.5
|
||||
'@tailwindcss/oxide': 4.0.5
|
||||
lightningcss: 1.29.1
|
||||
tailwindcss: 4.0.4
|
||||
tailwindcss: 4.0.5
|
||||
vite: 6.1.0(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(stylus@0.57.0)(yaml@2.7.0)
|
||||
|
||||
'@trysound/sax@0.2.0': {}
|
||||
|
@ -5876,13 +5876,13 @@ snapshots:
|
|||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier-plugin-tailwindcss@0.6.11(@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.4.2))(prettier@3.4.2):
|
||||
prettier-plugin-tailwindcss@0.6.11(@ianvs/prettier-plugin-sort-imports@4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.0))(prettier@3.5.0):
|
||||
dependencies:
|
||||
prettier: 3.4.2
|
||||
prettier: 3.5.0
|
||||
optionalDependencies:
|
||||
'@ianvs/prettier-plugin-sort-imports': 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.4.2)
|
||||
'@ianvs/prettier-plugin-sort-imports': 4.4.1(@vue/compiler-sfc@3.5.13)(prettier@3.5.0)
|
||||
|
||||
prettier@3.4.2: {}
|
||||
prettier@3.5.0: {}
|
||||
|
||||
prismjs@1.29.0: {}
|
||||
|
||||
|
@ -6001,7 +6001,7 @@ snapshots:
|
|||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
simple-icons@14.5.0: {}
|
||||
simple-icons@14.6.0: {}
|
||||
|
||||
sisteransi@1.0.5: {}
|
||||
|
||||
|
@ -6148,7 +6148,7 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
tailwindcss@4.0.4: {}
|
||||
tailwindcss@4.0.5: {}
|
||||
|
||||
tapable@2.2.1: {}
|
||||
|
||||
|
@ -6389,10 +6389,10 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vue-i18n@11.1.0(vue@3.5.13(typescript@5.7.3)):
|
||||
vue-i18n@11.1.1(vue@3.5.13(typescript@5.7.3)):
|
||||
dependencies:
|
||||
'@intlify/core-base': 11.1.0
|
||||
'@intlify/shared': 11.1.0
|
||||
'@intlify/core-base': 11.1.1
|
||||
'@intlify/shared': 11.1.1
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
|
||||
|
|
|
@ -677,7 +677,11 @@
|
|||
"none_desc": "Jedes Event erstellt Pipelines, einschließlich Pull-Requests. Diese Einstellung kann gefährlich sein und wird nur für private Instanzen empfohlen.",
|
||||
"pull_requests": "Alle Pull-Requests",
|
||||
"all_events": "Alle Ereignisse von der Forge",
|
||||
"desc": "Verhindere, dass bösartige Pipelines Geheimnisse preisgeben oder schädliche Aufgaben ausführen, indem du diese vor der Ausführung genehmigst."
|
||||
"desc": "Verhindere, dass bösartige Pipelines Geheimnisse preisgeben oder schädliche Aufgaben ausführen, indem du diese vor der Ausführung genehmigst.",
|
||||
"allowed_users": {
|
||||
"desc": "Pipelines von diesen Benutzern erfordern nie eine Genehmigung.",
|
||||
"allowed_users": "Zugelassene Benutzer"
|
||||
}
|
||||
},
|
||||
"org_access_denied": "Zugriff auf diese Organisation nicht erlaubt"
|
||||
}
|
||||
|
|
|
@ -55,6 +55,6 @@ const props = defineProps<{
|
|||
repo: Repo;
|
||||
}>();
|
||||
|
||||
const lastPipeline = computed(() => props.repo.last_pipeline_item);
|
||||
const lastPipeline = computed(() => props.repo.last_pipeline);
|
||||
const { since, shortMessage } = usePipeline(lastPipeline);
|
||||
</script>
|
||||
|
|
|
@ -9,19 +9,19 @@ export default function useRepos() {
|
|||
const lastAccess = useStorage('woodpecker:repo-last-access', new Map<number, number>());
|
||||
|
||||
function repoWithLastPipeline(repo: Repo): Repo {
|
||||
if (repo.last_pipeline === undefined) {
|
||||
if (repo.last_pipeline_number === undefined) {
|
||||
return repo;
|
||||
}
|
||||
|
||||
if (repo.last_pipeline_item?.number === repo.last_pipeline) {
|
||||
if (repo.last_pipeline?.number === repo.last_pipeline_number) {
|
||||
return repo;
|
||||
}
|
||||
|
||||
const lastPipeline = pipelineStore.getPipeline(ref(repo.id), ref(repo.last_pipeline)).value;
|
||||
const lastPipeline = pipelineStore.getPipeline(ref(repo.id), ref(repo.last_pipeline_number)).value;
|
||||
|
||||
return {
|
||||
...repo,
|
||||
last_pipeline_item: lastPipeline,
|
||||
last_pipeline: lastPipeline,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,8 +38,8 @@ export default function useRepos() {
|
|||
|
||||
function sortReposByLastActivity(repos: Repo[]): Repo[] {
|
||||
return repos.sort((a, b) => {
|
||||
const aLastActivity = a.last_pipeline_item?.created ?? 0;
|
||||
const bLastActivity = b.last_pipeline_item?.created ?? 0;
|
||||
const aLastActivity = a.last_pipeline?.created ?? 0;
|
||||
const bLastActivity = b.last_pipeline?.created ?? 0;
|
||||
return bLastActivity - aLastActivity;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -67,9 +67,9 @@ export interface Repo {
|
|||
|
||||
visibility: RepoVisibility;
|
||||
|
||||
last_pipeline?: number;
|
||||
last_pipeline_number?: number;
|
||||
|
||||
last_pipeline_item?: Pipeline;
|
||||
last_pipeline?: Pipeline;
|
||||
|
||||
require_approval: RepoRequireApproval;
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ export const usePipelineStore = defineStore('pipelines', () => {
|
|||
|
||||
// Update last pipeline number for the repo
|
||||
const repo = repoStore.repos.get(repoId);
|
||||
if (repo?.last_pipeline !== undefined && repo.last_pipeline < pipeline.number) {
|
||||
repo.last_pipeline = pipeline.number;
|
||||
if (repo?.last_pipeline_number !== undefined && repo.last_pipeline_number < pipeline.number) {
|
||||
repo.last_pipeline_number = pipeline.number;
|
||||
repoStore.setRepo(repo);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,16 +39,15 @@ export const useRepoStore = defineStore('repos', () => {
|
|||
|
||||
async function loadRepos() {
|
||||
const _ownedRepos = await apiClient.getRepoList();
|
||||
await Promise.all(
|
||||
_ownedRepos.map(async (repo) => {
|
||||
const lastPipeline = await apiClient.getPipelineList(repo.id, { page: 1, perPage: 1 });
|
||||
if (lastPipeline.length === 1) {
|
||||
pipelineStore.setPipeline(repo.id, lastPipeline[0]);
|
||||
repo.last_pipeline = lastPipeline[0].number;
|
||||
}
|
||||
setRepo(repo);
|
||||
}),
|
||||
);
|
||||
|
||||
_ownedRepos.forEach((repo) => {
|
||||
if (repo.last_pipeline) {
|
||||
pipelineStore.setPipeline(repo.id, repo.last_pipeline);
|
||||
repo.last_pipeline_number = repo.last_pipeline.number;
|
||||
}
|
||||
setRepo(repo);
|
||||
});
|
||||
|
||||
ownedRepoIds.value = _ownedRepos.map((repo) => repo.id);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue