Compare commits

...

11 Commits

21 changed files with 2862 additions and 57 deletions
+132
View File
@@ -0,0 +1,132 @@
query GetPipelines {
Pipelines {
id, name
}
}
query GetSecrets {
Secrets {
id, name
}
}
query GetRunners {
Runners {
id, name
}
}
query GetCloneCredentials {
CloneCredentials {
id, name, type
}
}
query GetPipeline(
$id: String!,
) {
Pipeline(
id: $id,
) {
id,
name,
url,
pollInterval,
cloneCredential {
id,
name,
type,
},
runs {
id,
inProgress,
result,
buildOutput,
stdout,
stderr,
}
}
}
mutation CreatePipeline(
$name: String!,
$url: String!,
$pollInterval: Int,
$cloneCredentialId: String,
) {
createPipeline(
name: $name,
url: $url,
pollInterval: $pollInterval,
cloneCredentialId: $cloneCredentialId,
) {
id,
name,
url,
pollInterval,
cloneCredential {
id,
name,
type,
}
}
}
mutation CreateCloneCredential(
$credentialType: String!,
$username: String!,
$secret: String!,
$name: String!,
) {
createCloneCredential(
type: $credentialType,
username: $username,
secret: $secret,
name: $name,
) {
type,
username,
secret,
name,
}
}
mutation CreateSecret(
$name: String!,
$secret: String!,
) {
createSecret(
name: $name,
secret: $secret,
) {
id,
name,
secret,
}
}
mutation CreateWebhook(
$webhookType: String!,
$pipelineId: String!,
) {
createWebhook(
type: $webhookType,
pipelineId: $pipelineId,
) {
id,
secret,
serverType,
}
}
mutation CreateRunner(
$name: String!,
) {
createRunner(
name: $name,
) {
id,
name,
token,
}
}
+8
View File
@@ -0,0 +1,8 @@
# Default genqlient config; for full documentation see:
# https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml
schema: schema.graphql
operations:
- genqlient.graphql
generated: queries/generated.go
package: queries
optional: pointer
+4
View File
@@ -3,6 +3,8 @@ module git.ohea.xyz/cursorius/tui
go 1.20 go 1.20
require ( require (
git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e
github.com/Khan/genqlient v0.5.0
github.com/charmbracelet/bubbles v0.15.0 github.com/charmbracelet/bubbles v0.15.0
github.com/charmbracelet/bubbletea v0.23.2 github.com/charmbracelet/bubbletea v0.23.2
github.com/charmbracelet/lipgloss v0.6.0 github.com/charmbracelet/lipgloss v0.6.0
@@ -20,8 +22,10 @@ require (
github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.14.0 // indirect github.com/muesli/termenv v0.14.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+112
View File
@@ -1,8 +1,27 @@
git.ohea.xyz/golang/config v0.0.0-20221002005232-8a901413a8b0 h1:a8ygEuzmqFDxXmf+e1IseDKBcAtkaIwfL3k4PIVVVr8=
git.ohea.xyz/golang/config v0.0.0-20221002005232-8a901413a8b0/go.mod h1:86PbXJ2WdqQ+3hYqrnv3ukgKNRK9nQfThnlY03FAO0g=
git.ohea.xyz/golang/config v0.0.0-20230225082201-095f317865a2 h1:B0nZl+J2d38+mjC4+eeMDl9S1OXPntqDwm8Kf8WIXL0=
git.ohea.xyz/golang/config v0.0.0-20230225082201-095f317865a2/go.mod h1:86PbXJ2WdqQ+3hYqrnv3ukgKNRK9nQfThnlY03FAO0g=
git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e h1:Hwv4cSg2+VG7vk7uOS/WqGIGySmW1xpjs0blo6dfHYc=
git.ohea.xyz/golang/config v0.0.0-20230225082310-91f0f601076e/go.mod h1:86PbXJ2WdqQ+3hYqrnv3ukgKNRK9nQfThnlY03FAO0g=
github.com/99designs/gqlgen v0.17.2/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Khan/genqlient v0.5.0 h1:TMZJ+tl/BpbmGyIBiXzKzUftDhw4ZWxQZ+1ydn0gyII=
github.com/Khan/genqlient v0.5.0/go.mod h1:EpIvDVXYm01GP6AXzjA7dKriPTH6GmtpmvTAwUUqIX8=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM=
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E= github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E=
github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI=
github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74=
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
@@ -13,10 +32,27 @@ github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87ini
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
@@ -28,6 +64,7 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -39,21 +76,96 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0= github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0=
github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
github.com/vektah/gqlparser/v2 v2.4.5 h1:C02NsyEsL4TXJB7ndonqTfuQOL4XPIu0aAWugdmTgmc=
github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+38 -19
View File
@@ -4,8 +4,10 @@ import (
"fmt" "fmt"
"os" "os"
"git.ohea.xyz/cursorius/tui/screens"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"git.ohea.xyz/cursorius/tui/screens"
"git.ohea.xyz/cursorius/tui/settings"
) )
type model struct { type model struct {
@@ -37,6 +39,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Height: m.height, Height: m.height,
} }
} }
case error:
m.screen = screens.ErrorScreen{
Err: msg,
}
return m, nil
} }
var cmd tea.Cmd var cmd tea.Cmd
@@ -50,26 +57,38 @@ func (m model) View() string {
} }
func main() { func main() {
conf, err := settings.GetConfig()
if err != nil {
fmt.Printf("Error: %v", err)
return
}
initialModel := model{ initialModel := model{
screen: screens.CreateLogin( screen: screens.CreateLogin(
// TODO: load from config file conf,
[]screens.CursoriusServer{ //[]screens.CursoriusServer{
screens.CursoriusServer{ // {
Name: "ohea", // Name: "local-test",
Url: "https://ci.cursorius.server", // Url: "http://127.0.0.1:45421/graphql",
Token: "test", // Token: "",
}, // },
screens.CursoriusServer{ // {
Name: "nohea", // Name: "ohea",
Url: "https://ci.cursoriuspreview.server", // Url: "https://ci.cursorius.server",
Token: "test", // Token: "test",
}, // },
screens.CursoriusServer{ // {
Name: "work", // Name: "nohea",
Url: "https://ci.acme.corp", // Url: "https://ci.cursoriuspreview.server",
Token: "test", // Token: "test",
}, // },
}, // {
// Name: "work",
// Url: "https://ci.acme.corp",
// Token: "test",
// },
//},
), ),
} }
+860
View File
@@ -0,0 +1,860 @@
// Code generated by github.com/Khan/genqlient, DO NOT EDIT.
package queries
import (
"context"
"github.com/Khan/genqlient/graphql"
)
// CreateCloneCredentialCreateCloneCredential includes the requested fields of the GraphQL type CloneCredential.
// The GraphQL type's documentation follows.
//
// A credential for authenticating with the pipeline source host.
type CreateCloneCredentialCreateCloneCredential struct {
// The credential type.
Type string `json:"type"`
// The username to user with the credential.
Username string `json:"username"`
// The secret for the credential.
Secret string `json:"secret"`
// The name of the credential.
Name string `json:"name"`
}
// GetType returns CreateCloneCredentialCreateCloneCredential.Type, and is useful for accessing the field via an interface.
func (v *CreateCloneCredentialCreateCloneCredential) GetType() string { return v.Type }
// GetUsername returns CreateCloneCredentialCreateCloneCredential.Username, and is useful for accessing the field via an interface.
func (v *CreateCloneCredentialCreateCloneCredential) GetUsername() string { return v.Username }
// GetSecret returns CreateCloneCredentialCreateCloneCredential.Secret, and is useful for accessing the field via an interface.
func (v *CreateCloneCredentialCreateCloneCredential) GetSecret() string { return v.Secret }
// GetName returns CreateCloneCredentialCreateCloneCredential.Name, and is useful for accessing the field via an interface.
func (v *CreateCloneCredentialCreateCloneCredential) GetName() string { return v.Name }
// CreateCloneCredentialResponse is returned by CreateCloneCredential on success.
type CreateCloneCredentialResponse struct {
// Create a new CloneCredential
CreateCloneCredential *CreateCloneCredentialCreateCloneCredential `json:"createCloneCredential"`
}
// GetCreateCloneCredential returns CreateCloneCredentialResponse.CreateCloneCredential, and is useful for accessing the field via an interface.
func (v *CreateCloneCredentialResponse) GetCreateCloneCredential() *CreateCloneCredentialCreateCloneCredential {
return v.CreateCloneCredential
}
// CreatePipelineCreatePipeline includes the requested fields of the GraphQL type Pipeline.
// The GraphQL type's documentation follows.
//
// A pipeline for running ci jobs
type CreatePipelineCreatePipeline struct {
// The id of the pipeline.
Id string `json:"id"`
// The name of the pipeline.
Name string `json:"name"`
// The url of the pipeline.
Url string `json:"url"`
// The polling interval for the pipeline.
PollInterval int `json:"pollInterval"`
// The configured credential for cloning the pipeline source.
CloneCredential *CreatePipelineCreatePipelineCloneCredential `json:"cloneCredential"`
}
// GetId returns CreatePipelineCreatePipeline.Id, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipeline) GetId() string { return v.Id }
// GetName returns CreatePipelineCreatePipeline.Name, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipeline) GetName() string { return v.Name }
// GetUrl returns CreatePipelineCreatePipeline.Url, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipeline) GetUrl() string { return v.Url }
// GetPollInterval returns CreatePipelineCreatePipeline.PollInterval, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipeline) GetPollInterval() int { return v.PollInterval }
// GetCloneCredential returns CreatePipelineCreatePipeline.CloneCredential, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipeline) GetCloneCredential() *CreatePipelineCreatePipelineCloneCredential {
return v.CloneCredential
}
// CreatePipelineCreatePipelineCloneCredential includes the requested fields of the GraphQL type CloneCredential.
// The GraphQL type's documentation follows.
//
// A credential for authenticating with the pipeline source host.
type CreatePipelineCreatePipelineCloneCredential struct {
// The id of the credential.
Id string `json:"id"`
// The name of the credential.
Name string `json:"name"`
// The credential type.
Type string `json:"type"`
}
// GetId returns CreatePipelineCreatePipelineCloneCredential.Id, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipelineCloneCredential) GetId() string { return v.Id }
// GetName returns CreatePipelineCreatePipelineCloneCredential.Name, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipelineCloneCredential) GetName() string { return v.Name }
// GetType returns CreatePipelineCreatePipelineCloneCredential.Type, and is useful for accessing the field via an interface.
func (v *CreatePipelineCreatePipelineCloneCredential) GetType() string { return v.Type }
// CreatePipelineResponse is returned by CreatePipeline on success.
type CreatePipelineResponse struct {
// Create a new pipeline
CreatePipeline *CreatePipelineCreatePipeline `json:"createPipeline"`
}
// GetCreatePipeline returns CreatePipelineResponse.CreatePipeline, and is useful for accessing the field via an interface.
func (v *CreatePipelineResponse) GetCreatePipeline() *CreatePipelineCreatePipeline {
return v.CreatePipeline
}
// CreateRunnerCreateRunner includes the requested fields of the GraphQL type Runner.
// The GraphQL type's documentation follows.
//
// A runner available for use inside of a pipeline.
type CreateRunnerCreateRunner struct {
// The id of the runner.
Id string `json:"id"`
// The name of the runner.
Name string `json:"name"`
// The token.
Token string `json:"token"`
}
// GetId returns CreateRunnerCreateRunner.Id, and is useful for accessing the field via an interface.
func (v *CreateRunnerCreateRunner) GetId() string { return v.Id }
// GetName returns CreateRunnerCreateRunner.Name, and is useful for accessing the field via an interface.
func (v *CreateRunnerCreateRunner) GetName() string { return v.Name }
// GetToken returns CreateRunnerCreateRunner.Token, and is useful for accessing the field via an interface.
func (v *CreateRunnerCreateRunner) GetToken() string { return v.Token }
// CreateRunnerResponse is returned by CreateRunner on success.
type CreateRunnerResponse struct {
// Create a new runner
CreateRunner *CreateRunnerCreateRunner `json:"createRunner"`
}
// GetCreateRunner returns CreateRunnerResponse.CreateRunner, and is useful for accessing the field via an interface.
func (v *CreateRunnerResponse) GetCreateRunner() *CreateRunnerCreateRunner { return v.CreateRunner }
// CreateSecretCreateSecret includes the requested fields of the GraphQL type Secret.
// The GraphQL type's documentation follows.
//
// A secret available for use inside of a pipeline.
type CreateSecretCreateSecret struct {
// The id of the secret.
Id string `json:"id"`
// The name of the secret.
Name string `json:"name"`
// The secret.
Secret string `json:"secret"`
}
// GetId returns CreateSecretCreateSecret.Id, and is useful for accessing the field via an interface.
func (v *CreateSecretCreateSecret) GetId() string { return v.Id }
// GetName returns CreateSecretCreateSecret.Name, and is useful for accessing the field via an interface.
func (v *CreateSecretCreateSecret) GetName() string { return v.Name }
// GetSecret returns CreateSecretCreateSecret.Secret, and is useful for accessing the field via an interface.
func (v *CreateSecretCreateSecret) GetSecret() string { return v.Secret }
// CreateSecretResponse is returned by CreateSecret on success.
type CreateSecretResponse struct {
// Create a new secret
CreateSecret *CreateSecretCreateSecret `json:"createSecret"`
}
// GetCreateSecret returns CreateSecretResponse.CreateSecret, and is useful for accessing the field via an interface.
func (v *CreateSecretResponse) GetCreateSecret() *CreateSecretCreateSecret { return v.CreateSecret }
// CreateWebhookCreateWebhook includes the requested fields of the GraphQL type Webhook.
// The GraphQL type's documentation follows.
//
// A webhook for triggering pipelines
type CreateWebhookCreateWebhook struct {
// The id of the webhook.
Id string `json:"id"`
// The secret used to validate the webhook.
Secret string `json:"secret"`
// The format of the webhook.
ServerType string `json:"serverType"`
}
// GetId returns CreateWebhookCreateWebhook.Id, and is useful for accessing the field via an interface.
func (v *CreateWebhookCreateWebhook) GetId() string { return v.Id }
// GetSecret returns CreateWebhookCreateWebhook.Secret, and is useful for accessing the field via an interface.
func (v *CreateWebhookCreateWebhook) GetSecret() string { return v.Secret }
// GetServerType returns CreateWebhookCreateWebhook.ServerType, and is useful for accessing the field via an interface.
func (v *CreateWebhookCreateWebhook) GetServerType() string { return v.ServerType }
// CreateWebhookResponse is returned by CreateWebhook on success.
type CreateWebhookResponse struct {
// Create a new webhook
CreateWebhook *CreateWebhookCreateWebhook `json:"createWebhook"`
}
// GetCreateWebhook returns CreateWebhookResponse.CreateWebhook, and is useful for accessing the field via an interface.
func (v *CreateWebhookResponse) GetCreateWebhook() *CreateWebhookCreateWebhook {
return v.CreateWebhook
}
// GetCloneCredentialsCloneCredentialsCloneCredential includes the requested fields of the GraphQL type CloneCredential.
// The GraphQL type's documentation follows.
//
// A credential for authenticating with the pipeline source host.
type GetCloneCredentialsCloneCredentialsCloneCredential struct {
// The id of the credential.
Id string `json:"id"`
// The name of the credential.
Name string `json:"name"`
// The credential type.
Type string `json:"type"`
}
// GetId returns GetCloneCredentialsCloneCredentialsCloneCredential.Id, and is useful for accessing the field via an interface.
func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetId() string { return v.Id }
// GetName returns GetCloneCredentialsCloneCredentialsCloneCredential.Name, and is useful for accessing the field via an interface.
func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetName() string { return v.Name }
// GetType returns GetCloneCredentialsCloneCredentialsCloneCredential.Type, and is useful for accessing the field via an interface.
func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetType() string { return v.Type }
// GetCloneCredentialsResponse is returned by GetCloneCredentials on success.
type GetCloneCredentialsResponse struct {
CloneCredentials []*GetCloneCredentialsCloneCredentialsCloneCredential `json:"CloneCredentials"`
}
// GetCloneCredentials returns GetCloneCredentialsResponse.CloneCredentials, and is useful for accessing the field via an interface.
func (v *GetCloneCredentialsResponse) GetCloneCredentials() []*GetCloneCredentialsCloneCredentialsCloneCredential {
return v.CloneCredentials
}
// GetPipelinePipeline includes the requested fields of the GraphQL type Pipeline.
// The GraphQL type's documentation follows.
//
// A pipeline for running ci jobs
type GetPipelinePipeline struct {
// The id of the pipeline.
Id string `json:"id"`
// The name of the pipeline.
Name string `json:"name"`
// The url of the pipeline.
Url string `json:"url"`
// The polling interval for the pipeline.
PollInterval int `json:"pollInterval"`
// The configured credential for cloning the pipeline source.
CloneCredential *GetPipelinePipelineCloneCredential `json:"cloneCredential"`
// The list of runs for the pipeline.
Runs []GetPipelinePipelineRunsRun `json:"runs"`
}
// GetId returns GetPipelinePipeline.Id, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetId() string { return v.Id }
// GetName returns GetPipelinePipeline.Name, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetName() string { return v.Name }
// GetUrl returns GetPipelinePipeline.Url, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetUrl() string { return v.Url }
// GetPollInterval returns GetPipelinePipeline.PollInterval, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetPollInterval() int { return v.PollInterval }
// GetCloneCredential returns GetPipelinePipeline.CloneCredential, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetCloneCredential() *GetPipelinePipelineCloneCredential {
return v.CloneCredential
}
// GetRuns returns GetPipelinePipeline.Runs, and is useful for accessing the field via an interface.
func (v *GetPipelinePipeline) GetRuns() []GetPipelinePipelineRunsRun { return v.Runs }
// GetPipelinePipelineCloneCredential includes the requested fields of the GraphQL type CloneCredential.
// The GraphQL type's documentation follows.
//
// A credential for authenticating with the pipeline source host.
type GetPipelinePipelineCloneCredential struct {
// The id of the credential.
Id string `json:"id"`
// The name of the credential.
Name string `json:"name"`
// The credential type.
Type string `json:"type"`
}
// GetId returns GetPipelinePipelineCloneCredential.Id, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineCloneCredential) GetId() string { return v.Id }
// GetName returns GetPipelinePipelineCloneCredential.Name, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineCloneCredential) GetName() string { return v.Name }
// GetType returns GetPipelinePipelineCloneCredential.Type, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineCloneCredential) GetType() string { return v.Type }
// GetPipelinePipelineRunsRun includes the requested fields of the GraphQL type Run.
// The GraphQL type's documentation follows.
//
// A pipeline run
type GetPipelinePipelineRunsRun struct {
// The id of the run.
Id string `json:"id"`
// The progress status of the run.
InProgress *bool `json:"inProgress"`
// The result of the run.
Result *float64 `json:"result"`
// Logs of the top level container build for the run.
BuildOutput *string `json:"buildOutput"`
// The stdout used to validate the run.
Stdout *string `json:"stdout"`
// The stderr used to validate the run.
Stderr *string `json:"stderr"`
}
// GetId returns GetPipelinePipelineRunsRun.Id, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetId() string { return v.Id }
// GetInProgress returns GetPipelinePipelineRunsRun.InProgress, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetInProgress() *bool { return v.InProgress }
// GetResult returns GetPipelinePipelineRunsRun.Result, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetResult() *float64 { return v.Result }
// GetBuildOutput returns GetPipelinePipelineRunsRun.BuildOutput, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetBuildOutput() *string { return v.BuildOutput }
// GetStdout returns GetPipelinePipelineRunsRun.Stdout, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetStdout() *string { return v.Stdout }
// GetStderr returns GetPipelinePipelineRunsRun.Stderr, and is useful for accessing the field via an interface.
func (v *GetPipelinePipelineRunsRun) GetStderr() *string { return v.Stderr }
// GetPipelineResponse is returned by GetPipeline on success.
type GetPipelineResponse struct {
Pipeline *GetPipelinePipeline `json:"Pipeline"`
}
// GetPipeline returns GetPipelineResponse.Pipeline, and is useful for accessing the field via an interface.
func (v *GetPipelineResponse) GetPipeline() *GetPipelinePipeline { return v.Pipeline }
// GetPipelinesPipelinesPipeline includes the requested fields of the GraphQL type Pipeline.
// The GraphQL type's documentation follows.
//
// A pipeline for running ci jobs
type GetPipelinesPipelinesPipeline struct {
// The id of the pipeline.
Id string `json:"id"`
// The name of the pipeline.
Name string `json:"name"`
}
// GetId returns GetPipelinesPipelinesPipeline.Id, and is useful for accessing the field via an interface.
func (v *GetPipelinesPipelinesPipeline) GetId() string { return v.Id }
// GetName returns GetPipelinesPipelinesPipeline.Name, and is useful for accessing the field via an interface.
func (v *GetPipelinesPipelinesPipeline) GetName() string { return v.Name }
// GetPipelinesResponse is returned by GetPipelines on success.
type GetPipelinesResponse struct {
Pipelines []*GetPipelinesPipelinesPipeline `json:"Pipelines"`
}
// GetPipelines returns GetPipelinesResponse.Pipelines, and is useful for accessing the field via an interface.
func (v *GetPipelinesResponse) GetPipelines() []*GetPipelinesPipelinesPipeline { return v.Pipelines }
// GetRunnersResponse is returned by GetRunners on success.
type GetRunnersResponse struct {
Runners []*GetRunnersRunnersRunner `json:"Runners"`
}
// GetRunners returns GetRunnersResponse.Runners, and is useful for accessing the field via an interface.
func (v *GetRunnersResponse) GetRunners() []*GetRunnersRunnersRunner { return v.Runners }
// GetRunnersRunnersRunner includes the requested fields of the GraphQL type Runner.
// The GraphQL type's documentation follows.
//
// A runner available for use inside of a pipeline.
type GetRunnersRunnersRunner struct {
// The id of the runner.
Id string `json:"id"`
// The name of the runner.
Name string `json:"name"`
}
// GetId returns GetRunnersRunnersRunner.Id, and is useful for accessing the field via an interface.
func (v *GetRunnersRunnersRunner) GetId() string { return v.Id }
// GetName returns GetRunnersRunnersRunner.Name, and is useful for accessing the field via an interface.
func (v *GetRunnersRunnersRunner) GetName() string { return v.Name }
// GetSecretsResponse is returned by GetSecrets on success.
type GetSecretsResponse struct {
Secrets []*GetSecretsSecretsSecret `json:"Secrets"`
}
// GetSecrets returns GetSecretsResponse.Secrets, and is useful for accessing the field via an interface.
func (v *GetSecretsResponse) GetSecrets() []*GetSecretsSecretsSecret { return v.Secrets }
// GetSecretsSecretsSecret includes the requested fields of the GraphQL type Secret.
// The GraphQL type's documentation follows.
//
// A secret available for use inside of a pipeline.
type GetSecretsSecretsSecret struct {
// The id of the secret.
Id string `json:"id"`
// The name of the secret.
Name string `json:"name"`
}
// GetId returns GetSecretsSecretsSecret.Id, and is useful for accessing the field via an interface.
func (v *GetSecretsSecretsSecret) GetId() string { return v.Id }
// GetName returns GetSecretsSecretsSecret.Name, and is useful for accessing the field via an interface.
func (v *GetSecretsSecretsSecret) GetName() string { return v.Name }
// __CreateCloneCredentialInput is used internally by genqlient
type __CreateCloneCredentialInput struct {
CredentialType string `json:"credentialType"`
Username string `json:"username"`
Secret string `json:"secret"`
Name string `json:"name"`
}
// GetCredentialType returns __CreateCloneCredentialInput.CredentialType, and is useful for accessing the field via an interface.
func (v *__CreateCloneCredentialInput) GetCredentialType() string { return v.CredentialType }
// GetUsername returns __CreateCloneCredentialInput.Username, and is useful for accessing the field via an interface.
func (v *__CreateCloneCredentialInput) GetUsername() string { return v.Username }
// GetSecret returns __CreateCloneCredentialInput.Secret, and is useful for accessing the field via an interface.
func (v *__CreateCloneCredentialInput) GetSecret() string { return v.Secret }
// GetName returns __CreateCloneCredentialInput.Name, and is useful for accessing the field via an interface.
func (v *__CreateCloneCredentialInput) GetName() string { return v.Name }
// __CreatePipelineInput is used internally by genqlient
type __CreatePipelineInput struct {
Name string `json:"name"`
Url string `json:"url"`
PollInterval *int `json:"pollInterval"`
CloneCredentialId *string `json:"cloneCredentialId"`
}
// GetName returns __CreatePipelineInput.Name, and is useful for accessing the field via an interface.
func (v *__CreatePipelineInput) GetName() string { return v.Name }
// GetUrl returns __CreatePipelineInput.Url, and is useful for accessing the field via an interface.
func (v *__CreatePipelineInput) GetUrl() string { return v.Url }
// GetPollInterval returns __CreatePipelineInput.PollInterval, and is useful for accessing the field via an interface.
func (v *__CreatePipelineInput) GetPollInterval() *int { return v.PollInterval }
// GetCloneCredentialId returns __CreatePipelineInput.CloneCredentialId, and is useful for accessing the field via an interface.
func (v *__CreatePipelineInput) GetCloneCredentialId() *string { return v.CloneCredentialId }
// __CreateRunnerInput is used internally by genqlient
type __CreateRunnerInput struct {
Name string `json:"name"`
}
// GetName returns __CreateRunnerInput.Name, and is useful for accessing the field via an interface.
func (v *__CreateRunnerInput) GetName() string { return v.Name }
// __CreateSecretInput is used internally by genqlient
type __CreateSecretInput struct {
Name string `json:"name"`
Secret string `json:"secret"`
}
// GetName returns __CreateSecretInput.Name, and is useful for accessing the field via an interface.
func (v *__CreateSecretInput) GetName() string { return v.Name }
// GetSecret returns __CreateSecretInput.Secret, and is useful for accessing the field via an interface.
func (v *__CreateSecretInput) GetSecret() string { return v.Secret }
// __CreateWebhookInput is used internally by genqlient
type __CreateWebhookInput struct {
WebhookType string `json:"webhookType"`
PipelineId string `json:"pipelineId"`
}
// GetWebhookType returns __CreateWebhookInput.WebhookType, and is useful for accessing the field via an interface.
func (v *__CreateWebhookInput) GetWebhookType() string { return v.WebhookType }
// GetPipelineId returns __CreateWebhookInput.PipelineId, and is useful for accessing the field via an interface.
func (v *__CreateWebhookInput) GetPipelineId() string { return v.PipelineId }
// __GetPipelineInput is used internally by genqlient
type __GetPipelineInput struct {
Id string `json:"id"`
}
// GetId returns __GetPipelineInput.Id, and is useful for accessing the field via an interface.
func (v *__GetPipelineInput) GetId() string { return v.Id }
func CreateCloneCredential(
ctx context.Context,
client graphql.Client,
credentialType string,
username string,
secret string,
name string,
) (*CreateCloneCredentialResponse, error) {
req := &graphql.Request{
OpName: "CreateCloneCredential",
Query: `
mutation CreateCloneCredential ($credentialType: String!, $username: String!, $secret: String!, $name: String!) {
createCloneCredential(type: $credentialType, username: $username, secret: $secret, name: $name) {
type
username
secret
name
}
}
`,
Variables: &__CreateCloneCredentialInput{
CredentialType: credentialType,
Username: username,
Secret: secret,
Name: name,
},
}
var err error
var data CreateCloneCredentialResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func CreatePipeline(
ctx context.Context,
client graphql.Client,
name string,
url string,
pollInterval *int,
cloneCredentialId *string,
) (*CreatePipelineResponse, error) {
req := &graphql.Request{
OpName: "CreatePipeline",
Query: `
mutation CreatePipeline ($name: String!, $url: String!, $pollInterval: Int, $cloneCredentialId: String) {
createPipeline(name: $name, url: $url, pollInterval: $pollInterval, cloneCredentialId: $cloneCredentialId) {
id
name
url
pollInterval
cloneCredential {
id
name
type
}
}
}
`,
Variables: &__CreatePipelineInput{
Name: name,
Url: url,
PollInterval: pollInterval,
CloneCredentialId: cloneCredentialId,
},
}
var err error
var data CreatePipelineResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func CreateRunner(
ctx context.Context,
client graphql.Client,
name string,
) (*CreateRunnerResponse, error) {
req := &graphql.Request{
OpName: "CreateRunner",
Query: `
mutation CreateRunner ($name: String!) {
createRunner(name: $name) {
id
name
token
}
}
`,
Variables: &__CreateRunnerInput{
Name: name,
},
}
var err error
var data CreateRunnerResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func CreateSecret(
ctx context.Context,
client graphql.Client,
name string,
secret string,
) (*CreateSecretResponse, error) {
req := &graphql.Request{
OpName: "CreateSecret",
Query: `
mutation CreateSecret ($name: String!, $secret: String!) {
createSecret(name: $name, secret: $secret) {
id
name
secret
}
}
`,
Variables: &__CreateSecretInput{
Name: name,
Secret: secret,
},
}
var err error
var data CreateSecretResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func CreateWebhook(
ctx context.Context,
client graphql.Client,
webhookType string,
pipelineId string,
) (*CreateWebhookResponse, error) {
req := &graphql.Request{
OpName: "CreateWebhook",
Query: `
mutation CreateWebhook ($webhookType: String!, $pipelineId: String!) {
createWebhook(type: $webhookType, pipelineId: $pipelineId) {
id
secret
serverType
}
}
`,
Variables: &__CreateWebhookInput{
WebhookType: webhookType,
PipelineId: pipelineId,
},
}
var err error
var data CreateWebhookResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func GetCloneCredentials(
ctx context.Context,
client graphql.Client,
) (*GetCloneCredentialsResponse, error) {
req := &graphql.Request{
OpName: "GetCloneCredentials",
Query: `
query GetCloneCredentials {
CloneCredentials {
id
name
type
}
}
`,
}
var err error
var data GetCloneCredentialsResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func GetPipeline(
ctx context.Context,
client graphql.Client,
id string,
) (*GetPipelineResponse, error) {
req := &graphql.Request{
OpName: "GetPipeline",
Query: `
query GetPipeline ($id: String!) {
Pipeline(id: $id) {
id
name
url
pollInterval
cloneCredential {
id
name
type
}
runs {
id
inProgress
result
buildOutput
stdout
stderr
}
}
}
`,
Variables: &__GetPipelineInput{
Id: id,
},
}
var err error
var data GetPipelineResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func GetPipelines(
ctx context.Context,
client graphql.Client,
) (*GetPipelinesResponse, error) {
req := &graphql.Request{
OpName: "GetPipelines",
Query: `
query GetPipelines {
Pipelines {
id
name
}
}
`,
}
var err error
var data GetPipelinesResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func GetRunners(
ctx context.Context,
client graphql.Client,
) (*GetRunnersResponse, error) {
req := &graphql.Request{
OpName: "GetRunners",
Query: `
query GetRunners {
Runners {
id
name
}
}
`,
}
var err error
var data GetRunnersResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
func GetSecrets(
ctx context.Context,
client graphql.Client,
) (*GetSecretsResponse, error) {
req := &graphql.Request{
OpName: "GetSecrets",
Query: `
query GetSecrets {
Secrets {
id
name
}
}
`,
}
var err error
var data GetSecretsResponse
resp := &graphql.Response{Data: &data}
err = client.MakeRequest(
ctx,
req,
resp,
)
return &data, err
}
+164
View File
@@ -0,0 +1,164 @@
schema {
query: Query
mutation: Mutation
}
"A secret available for use inside of a pipeline."
type Secret {
"The id of the secret."
id: String!
"The name of the secret."
name: String!
"The secret."
secret: String!
}
"A runner available for use inside of a pipeline."
type Runner {
"The id of the runner."
id: String!
"The name of the runner."
name: String!
"The token."
token: String!
}
""
type Query {
""
CloneCredential(
"The id of the requested credential."
id: String!
): CloneCredential
""
CloneCredentials: [CloneCredential]!
""
Pipeline(
"The id of the requested pipeline."
id: String!
): Pipeline
""
Pipelines: [Pipeline]!
""
Runners: [Runner]!
""
Secrets: [Secret]!
}
"A pipeline for running ci jobs"
type Pipeline {
"The configured credential for cloning the pipeline source."
cloneCredential: CloneCredential
"The id of the pipeline."
id: String!
"The name of the pipeline."
name: String!
"The polling interval for the pipeline."
pollInterval: Int!
"The list of runs for the pipeline."
runs: [Run!]!
"The list of secrets for the pipeline."
secrets: [Secret!]!
"The url of the pipeline."
url: String!
"The list of webhooks for the pipeline."
webhooks: [Webhook!]!
}
""
type Mutation {
"Allow a secret to be accessed by a pipeline."
addSecretToPipeline(
""
secretId: String,
""
pipelineId: String!
): Pipeline
"Create a new CloneCredential"
createCloneCredential(
""
type: String!,
""
username: String!,
""
secret: String!,
""
name: String!
): CloneCredential
"Create a new pipeline"
createPipeline(
""
name: String!,
""
url: String!,
""
pollInterval: Int,
""
cloneCredentialId: String
): Pipeline
"Create a new runner"
createRunner(
""
name: String!
): Runner
"Create a new secret"
createSecret(
""
name: String!,
""
secret: String!
): Secret
"Create a new webhook"
createWebhook(
""
type: String!,
""
pipelineId: String!
): Webhook
"Remove a pipeline's access to a secret."
removeSecretFromPipeline(
""
secretId: String,
""
pipelineId: String!
): Pipeline
"Set the CloneCredential used by a pipeline to clone the source repo"
setPipelineCloneCredential(
""
cloneCredentialId: String,
""
pipelineId: String!
): Pipeline
}
"A webhook for triggering pipelines"
type Webhook {
"The id of the webhook."
id: String!
"The secret used to validate the webhook."
secret: String!
"The format of the webhook."
serverType: String!
}
"A credential for authenticating with the pipeline source host."
type CloneCredential {
"The id of the credential."
id: String!
"The name of the credential."
name: String!
"The secret for the credential."
secret: String!
"The credential type."
type: String!
"The username to user with the credential."
username: String!
}
"A pipeline run"
type Run {
"Logs of the top level container build for the run."
buildOutput: String
"The id of the run."
id: String!
"The progress status of the run."
inProgress: Boolean
"The result of the run."
result: Float
"The stderr used to validate the run."
stderr: String
"The stdout used to validate the run."
stdout: String
}
+47 -19
View File
@@ -3,21 +3,23 @@ package screens
import ( import (
"fmt" "fmt"
"io" "io"
"net/http"
"strings" "strings"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
"git.ohea.xyz/cursorius/tui/settings"
"git.ohea.xyz/cursorius/tui/widget"
) )
type CursoriusServer struct { func ServerLogin(s settings.CursoriusServer) tea.Msg {
Name string dashboard, err := createDashboard(s)
Url string if err != nil {
Token string return err
} }
func (s CursoriusServer) Login() ScreenSwitchMsg {
dashboard := createDashboard(s)
return ScreenSwitchMsg{ return ScreenSwitchMsg{
NewScreen: dashboard, NewScreen: dashboard,
} }
@@ -43,10 +45,11 @@ var (
type Dashboard struct { type Dashboard struct {
Tabs []string Tabs []string
TabContent []list.Model TabContent []tea.Model
activeTab int activeTab int
width int width int
height int height int
client graphql.Client
} }
func (m Dashboard) Init() tea.Cmd { func (m Dashboard) Init() tea.Cmd {
@@ -59,8 +62,9 @@ func (m Dashboard) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.width = msg.Width m.width = msg.Width
m.height = msg.Height m.height = msg.Height
for i := 0; i < len(m.TabContent); i++ { for i := 0; i < len(m.TabContent); i++ {
m.TabContent[i].SetWidth(m.width - 10) m.TabContent[i].Update(msg)
m.TabContent[i].SetHeight(m.height - 10) // m.TabContent[i].SetWidth(m.width - 10)
// m.TabContent[i].SetHeight(m.height - 10)
} }
case tea.KeyMsg: case tea.KeyMsg:
switch keypress := msg.String(); keypress { switch keypress := msg.String(); keypress {
@@ -147,14 +151,37 @@ func (d dashboardItemDelegate) Render(w io.Writer, m list.Model, index int, list
fmt.Fprint(w, fn(str)) fmt.Fprint(w, fn(str))
} }
func createDashboard(s CursoriusServer) Dashboard { func createDashboard(s settings.CursoriusServer) (Dashboard, error) {
tabs := []string{"Pipelines", "Secrets", "Clone Credentials", "Runners"}
content := []list.Item{dashboardItem("Pipelines"), dashboardItem("Secrets"), dashboardItem("Clone Credentials"), dashboardItem("Runners")}
tabContent := []list.Model{ client := graphql.NewClient(s.Url, http.DefaultClient)
list.New(content, dashboardItemDelegate{}, 50, 50),
list.New(content, dashboardItemDelegate{}, 50, 50), tabs := []string{"Pipelines", "Secrets", "Clone Credentials", "Runners"}
list.New(content, dashboardItemDelegate{}, 50, 50),
pipelineWidget, err := widget.CreatePipelineWidget(client)
if err != nil {
return Dashboard{}, fmt.Errorf("Could not create Pipelines tab: %w", err)
}
//secretWidget, err := widget.CreateSecretWidget(client)
//if err != nil {
// return Dashboard{}, fmt.Errorf("Could not create Secrets tab: %w", err)
//}
//cloneCredentialWidget, err := widget.CreateCloneCredentialWidget(client)
//if err != nil {
// return Dashboard{}, fmt.Errorf("Could not create Clone Credentials tab: %w", err)
//}
//runnerWidget, err := widget.CreateRunnerWidget(client)
//if err != nil {
// return Dashboard{}, fmt.Errorf("Could not create Runner tab: %w", err)
//}
tabContent := []tea.Model{
pipelineWidget,
//secretWidget,
//cloneCredentialWidget,
//runnerWidget,
} }
return Dashboard{ return Dashboard{
@@ -162,7 +189,8 @@ func createDashboard(s CursoriusServer) Dashboard {
TabContent: tabContent, TabContent: tabContent,
width: 50, width: 50,
height: 50, height: 50,
} client: client,
}, nil
} }
func max(a, b int) int { func max(a, b int) int {
+13 -9
View File
@@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"io" "io"
"git.ohea.xyz/cursorius/tui/settings"
"git.ohea.xyz/golang/config"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textinput" "github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
@@ -11,7 +13,7 @@ import (
type EditServer struct { type EditServer struct {
entries list.Model entries list.Model
servers []CursoriusServer config config.Config[settings.Config]
pos int pos int
} }
@@ -77,15 +79,16 @@ func (m EditServer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
token = e.field.Value() token = e.field.Value()
} }
newServer := CursoriusServer{ newServer := settings.CursoriusServer{
Name: name, Name: name,
Url: url, Url: url,
Token: token, Token: token,
} }
m.servers[m.pos] = newServer m.config.Config.Servers[m.pos] = newServer
m.config.Write()
return m, func() tea.Msg { return m, func() tea.Msg {
return ScreenSwitchMsg{ return ScreenSwitchMsg{
NewScreen: CreateLogin(m.servers), NewScreen: CreateLogin(m.config),
} }
} }
} }
@@ -113,21 +116,21 @@ func (m EditServer) View() string {
return m.entries.View() return m.entries.View()
} }
func createEditServer(s []CursoriusServer, pos int) EditServer { func createEditServer(conf config.Config[settings.Config], pos int) EditServer {
nameField := textinput.New() nameField := textinput.New()
nameField.Focus() nameField.Focus()
nameField.Width = 20 nameField.Width = 20
nameField.Prompt = "Name: " nameField.Prompt = "Name: "
nameField.Placeholder = "Nickname" nameField.Placeholder = "Nickname"
nameField.SetValue(s[pos].Name) nameField.SetValue(conf.Config.Servers[pos].Name)
urlField := textinput.New() urlField := textinput.New()
urlField.Prompt = "Url: " urlField.Prompt = "Url: "
urlField.Placeholder = "https://ci.cursorius.ohea/" urlField.Placeholder = "https://ci.cursorius.ohea/"
urlField.SetValue(s[pos].Url) urlField.SetValue(conf.Config.Servers[pos].Url)
tokenField := textinput.New() tokenField := textinput.New()
tokenField.Prompt = "Token: " tokenField.Prompt = "Token: "
tokenField.Placeholder = "1234567890" tokenField.Placeholder = "1234567890"
tokenField.SetValue(s[pos].Token) tokenField.SetValue(conf.Config.Servers[pos].Token)
tokenField.EchoMode = textinput.EchoPassword tokenField.EchoMode = textinput.EchoPassword
items := []list.Item{ items := []list.Item{
entryItem{field: nameField}, entryItem{field: nameField},
@@ -142,9 +145,10 @@ func createEditServer(s []CursoriusServer, pos int) EditServer {
l.KeyMap.GoToEnd.SetEnabled(false) l.KeyMap.GoToEnd.SetEnabled(false)
l.KeyMap.CursorDown.SetKeys(append(l.KeyMap.CursorDown.Keys(), "tab")...) l.KeyMap.CursorDown.SetKeys(append(l.KeyMap.CursorDown.Keys(), "tab")...)
l.KeyMap.Filter.SetEnabled(false) l.KeyMap.Filter.SetEnabled(false)
l.KeyMap.Quit.SetEnabled(false)
e := EditServer{ e := EditServer{
entries: l, entries: l,
servers: s, config: conf,
pos: pos, pos: pos,
} }
return e return e
+19
View File
@@ -0,0 +1,19 @@
package screens
import tea "github.com/charmbracelet/bubbletea"
type ErrorScreen struct {
Err error
}
func (m ErrorScreen) Init() tea.Cmd {
return nil
}
func (m ErrorScreen) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m ErrorScreen) View() string {
return m.Err.Error()
}
+14 -10
View File
@@ -4,6 +4,9 @@ import (
"fmt" "fmt"
"io" "io"
"git.ohea.xyz/cursorius/tui/settings"
"git.ohea.xyz/golang/config"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
@@ -11,7 +14,7 @@ import (
type Login struct { type Login struct {
selected int selected int
servers []CursoriusServer config config.Config[settings.Config]
serverList list.Model serverList list.Model
} }
@@ -32,27 +35,28 @@ func (m Login) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.KeyMsg: case tea.KeyMsg:
switch msg.String() { switch msg.String() {
case "e": case "e":
if m.serverList.Index() < len(m.servers) { if m.serverList.Index() < len(m.config.Config.Servers) {
return m, func() tea.Msg { return m, func() tea.Msg {
return ScreenSwitchMsg{ return ScreenSwitchMsg{
NewScreen: createEditServer( NewScreen: createEditServer(
m.servers, m.config,
m.serverList.Index(), m.serverList.Index(),
), ),
} }
} }
} }
case "enter": case "enter":
if m.serverList.Index() < len(m.servers)-1 { if m.serverList.Index() < len(m.config.Config.Servers) {
return m, func() tea.Msg { return m, func() tea.Msg {
return m.servers[m.selected].Login() return ServerLogin(m.config.Config.Servers[m.serverList.Index()])
} }
} else { } else {
return m, func() tea.Msg { return m, func() tea.Msg {
m.config.Config.Servers = append(m.config.Config.Servers, settings.CursoriusServer{})
return ScreenSwitchMsg{ return ScreenSwitchMsg{
NewScreen: createEditServer( NewScreen: createEditServer(
append(m.servers, CursoriusServer{}), m.config,
len(m.servers), len(m.config.Config.Servers)-1,
), ),
} }
} }
@@ -114,9 +118,9 @@ func (d loginItemDelegate) Render(w io.Writer, m list.Model, index int, listItem
fmt.Fprint(w, fn(str)) fmt.Fprint(w, fn(str))
} }
func CreateLogin(servers []CursoriusServer) Login { func CreateLogin(conf config.Config[settings.Config]) Login {
items := []list.Item{} items := []list.Item{}
for _, server := range servers { for _, server := range conf.Config.Servers {
items = append( items = append(
items, items,
serverItem{ serverItem{
@@ -137,7 +141,7 @@ func CreateLogin(servers []CursoriusServer) Login {
return Login{ return Login{
selected: 0, selected: 0,
servers: servers, config: conf,
serverList: l, serverList: l,
} }
} }
+28
View File
@@ -0,0 +1,28 @@
package settings
import "git.ohea.xyz/golang/config"
type CursoriusServer struct {
Name string
Url string
Token string
}
type Config struct {
Servers []CursoriusServer
}
func GetConfig() (config.Config[Config], error) {
conf := config.Config[Config]{
Name: "cursorius",
Filename: "tui",
Config: Config{},
}
_, err := conf.Get()
if err != nil {
return config.Config[Config]{}, err
}
return conf, nil
}
+537
View File
@@ -0,0 +1,537 @@
diff --git a/genqlient.graphql b/genqlient.graphql
index 12e2b80..5bf5e9a 100644
--- a/genqlient.graphql
+++ b/genqlient.graphql
@@ -22,6 +22,31 @@ query GetCloneCredentials {
}
}

+query GetPipeline(
+ $id: String!,
+) {
+ Pipeline(
+ id: $id,
+ ) {
+ id,
+ name,
+ url,
+ pollInterval,
+ cloneCredential {
+ id,
+ name,
+ type,
+ },
+ runs {
+ id,
+ inProgress,
+ result,
+ buildOutput,
+ stdout,
+ stderr,
+ }
+ }
+}

mutation CreatePipeline(
$name: String!,
diff --git a/go.mod b/go.mod
index a29c87c..4584f76 100644
--- a/go.mod
+++ b/go.mod
@@ -3,16 +3,13 @@ module git.ohea.xyz/cursorius/tui
go 1.20

require (
+ github.com/Khan/genqlient v0.5.0
github.com/charmbracelet/bubbles v0.15.0
github.com/charmbracelet/bubbletea v0.23.2
github.com/charmbracelet/lipgloss v0.6.0
)

require (
- github.com/Khan/genqlient v0.5.0 // indirect
- github.com/agnivade/levenshtein v1.1.1 // indirect
- github.com/alexflint/go-arg v1.4.2 // indirect
- github.com/alexflint/go-scalar v1.0.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
github.com/containerd/console v1.0.3 // indirect
@@ -27,12 +24,8 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/vektah/gqlparser/v2 v2.4.5 // indirect
- golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
- golang.org/x/tools v0.1.10 // indirect
- golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/go.sum b/go.sum
index 5c4ba8d..3c5c5da 100644
--- a/go.sum
+++ b/go.sum
@@ -4,12 +4,10 @@ github.com/Khan/genqlient v0.5.0 h1:TMZJ+tl/BpbmGyIBiXzKzUftDhw4ZWxQZ+1ydn0gyII=
github.com/Khan/genqlient v0.5.0/go.mod h1:EpIvDVXYm01GP6AXzjA7dKriPTH6GmtpmvTAwUUqIX8=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
-github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
-github.com/alexflint/go-arg v1.4.2 h1:lDWZAXxpAnZUq4qwb86p/3rIJJ2Li81EoMbTMujhVa0=
github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM=
-github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70=
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
@@ -31,6 +29,7 @@ github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkX
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -71,6 +70,7 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0=
github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
@@ -79,6 +79,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -86,6 +87,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
@@ -99,7 +101,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -138,12 +139,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -151,6 +150,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/queries/generated.go b/queries/generated.go
index 31eb59c..8f2ad79 100644
--- a/queries/generated.go
+++ b/queries/generated.go
@@ -240,6 +240,112 @@ func (v *GetCloneCredentialsResponse) GetCloneCredentials() []*GetCloneCredentia
return v.CloneCredentials
}

+// GetPipelinePipeline includes the requested fields of the GraphQL type Pipeline.
+// The GraphQL type's documentation follows.
+//
+// A pipeline for running ci jobs
+type GetPipelinePipeline struct {
+ // The id of the pipeline.
+ Id string `json:"id"`
+ // The name of the pipeline.
+ Name string `json:"name"`
+ // The url of the pipeline.
+ Url string `json:"url"`
+ // The polling interval for the pipeline.
+ PollInterval int `json:"pollInterval"`
+ // The configured credential for cloning the pipeline source.
+ CloneCredential *GetPipelinePipelineCloneCredential `json:"cloneCredential"`
+ // The list of runs for the pipeline.
+ Runs []GetPipelinePipelineRunsRun `json:"runs"`
+}
+
+// GetId returns GetPipelinePipeline.Id, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetId() string { return v.Id }
+
+// GetName returns GetPipelinePipeline.Name, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetName() string { return v.Name }
+
+// GetUrl returns GetPipelinePipeline.Url, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetUrl() string { return v.Url }
+
+// GetPollInterval returns GetPipelinePipeline.PollInterval, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetPollInterval() int { return v.PollInterval }
+
+// GetCloneCredential returns GetPipelinePipeline.CloneCredential, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetCloneCredential() *GetPipelinePipelineCloneCredential {
+ return v.CloneCredential
+}
+
+// GetRuns returns GetPipelinePipeline.Runs, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipeline) GetRuns() []GetPipelinePipelineRunsRun { return v.Runs }
+
+// GetPipelinePipelineCloneCredential includes the requested fields of the GraphQL type CloneCredential.
+// The GraphQL type's documentation follows.
+//
+// A credential for authenticating with the pipeline source host.
+type GetPipelinePipelineCloneCredential struct {
+ // The id of the credential.
+ Id string `json:"id"`
+ // The name of the credential.
+ Name string `json:"name"`
+ // The credential type.
+ Type string `json:"type"`
+}
+
+// GetId returns GetPipelinePipelineCloneCredential.Id, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineCloneCredential) GetId() string { return v.Id }
+
+// GetName returns GetPipelinePipelineCloneCredential.Name, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineCloneCredential) GetName() string { return v.Name }
+
+// GetType returns GetPipelinePipelineCloneCredential.Type, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineCloneCredential) GetType() string { return v.Type }
+
+// GetPipelinePipelineRunsRun includes the requested fields of the GraphQL type Run.
+// The GraphQL type's documentation follows.
+//
+// A pipeline run
+type GetPipelinePipelineRunsRun struct {
+ // The id of the run.
+ Id string `json:"id"`
+ // The progress status of the run.
+ InProgress *bool `json:"inProgress"`
+ // The result of the run.
+ Result *float64 `json:"result"`
+ // Logs of the top level container build for the run.
+ BuildOutput *string `json:"buildOutput"`
+ // The stdout used to validate the run.
+ Stdout *string `json:"stdout"`
+ // The stderr used to validate the run.
+ Stderr *string `json:"stderr"`
+}
+
+// GetId returns GetPipelinePipelineRunsRun.Id, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetId() string { return v.Id }
+
+// GetInProgress returns GetPipelinePipelineRunsRun.InProgress, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetInProgress() *bool { return v.InProgress }
+
+// GetResult returns GetPipelinePipelineRunsRun.Result, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetResult() *float64 { return v.Result }
+
+// GetBuildOutput returns GetPipelinePipelineRunsRun.BuildOutput, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetBuildOutput() *string { return v.BuildOutput }
+
+// GetStdout returns GetPipelinePipelineRunsRun.Stdout, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetStdout() *string { return v.Stdout }
+
+// GetStderr returns GetPipelinePipelineRunsRun.Stderr, and is useful for accessing the field via an interface.
+func (v *GetPipelinePipelineRunsRun) GetStderr() *string { return v.Stderr }
+
+// GetPipelineResponse is returned by GetPipeline on success.
+type GetPipelineResponse struct {
+ Pipeline *GetPipelinePipeline `json:"Pipeline"`
+}
+
+// GetPipeline returns GetPipelineResponse.Pipeline, and is useful for accessing the field via an interface.
+func (v *GetPipelineResponse) GetPipeline() *GetPipelinePipeline { return v.Pipeline }
+
// GetPipelinesPipelinesPipeline includes the requested fields of the GraphQL type Pipeline.
// The GraphQL type's documentation follows.
//
@@ -387,6 +493,14 @@ func (v *__CreateWebhookInput) GetWebhookType() string { return v.WebhookType }
// GetPipelineId returns __CreateWebhookInput.PipelineId, and is useful for accessing the field via an interface.
func (v *__CreateWebhookInput) GetPipelineId() string { return v.PipelineId }

+// __GetPipelineInput is used internally by genqlient
+type __GetPipelineInput struct {
+ Id string `json:"id"`
+}
+
+// GetId returns __GetPipelineInput.Id, and is useful for accessing the field via an interface.
+func (v *__GetPipelineInput) GetId() string { return v.Id }
+
func CreateCloneCredential(
ctx context.Context,
client graphql.Client,
@@ -610,6 +724,54 @@ query GetCloneCredentials {
return &data, err
}

+func GetPipeline(
+ ctx context.Context,
+ client graphql.Client,
+ id string,
+) (*GetPipelineResponse, error) {
+ req := &graphql.Request{
+ OpName: "GetPipeline",
+ Query: `
+query GetPipeline ($id: String!) {
+ Pipeline(id: $id) {
+ id
+ name
+ url
+ pollInterval
+ cloneCredential {
+ id
+ name
+ type
+ }
+ runs {
+ id
+ inProgress
+ result
+ buildOutput
+ stdout
+ stderr
+ }
+ }
+}
+`,
+ Variables: &__GetPipelineInput{
+ Id: id,
+ },
+ }
+ var err error
+
+ var data GetPipelineResponse
+ resp := &graphql.Response{Data: &data}
+
+ err = client.MakeRequest(
+ ctx,
+ req,
+ resp,
+ )
+
+ return &data, err
+}
+
func GetPipelines(
ctx context.Context,
client graphql.Client,
diff --git a/schema.graphql b/schema.graphql
index 493b8a8..3e53e4c 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -2,27 +2,63 @@ schema {
query: Query
mutation: Mutation
}
-"A credential for authenticating with the pipeline source host."
-type CloneCredential {
- "The id of the credential."
+"A secret available for use inside of a pipeline."
+type Secret {
+ "The id of the secret."
id: String!
- "The name of the credential."
+ "The name of the secret."
name: String!
- "The secret for the credential."
+ "The secret."
secret: String!
- "The credential type."
- type: String!
- "The username to user with the credential."
- username: String!
}
-"A webhook for triggering pipelines"
-type Webhook {
- "The id of the webhook."
+"A runner available for use inside of a pipeline."
+type Runner {
+ "The id of the runner."
id: String!
- "The secret used to validate the webhook."
- secret: String!
- "The format of the webhook."
- serverType: String!
+ "The name of the runner."
+ name: String!
+ "The token."
+ token: String!
+}
+""
+type Query {
+ ""
+ CloneCredential(
+ "The id of the requested credential."
+ id: String!
+ ): CloneCredential
+ ""
+ CloneCredentials: [CloneCredential]!
+ ""
+ Pipeline(
+ "The id of the requested pipeline."
+ id: String!
+ ): Pipeline
+ ""
+ Pipelines: [Pipeline]!
+ ""
+ Runners: [Runner]!
+ ""
+ Secrets: [Secret]!
+}
+"A pipeline for running ci jobs"
+type Pipeline {
+ "The configured credential for cloning the pipeline source."
+ cloneCredential: CloneCredential
+ "The id of the pipeline."
+ id: String!
+ "The name of the pipeline."
+ name: String!
+ "The polling interval for the pipeline."
+ pollInterval: Int!
+ "The list of runs for the pipeline."
+ runs: [Run!]!
+ "The list of secrets for the pipeline."
+ secrets: [Secret!]!
+ "The url of the pipeline."
+ url: String!
+ "The list of webhooks for the pipeline."
+ webhooks: [Webhook!]!
}
""
type Mutation {
@@ -89,66 +125,32 @@ type Mutation {
pipelineId: String!
): Pipeline
}
-"A runner available for use inside of a pipeline."
-type Runner {
- "The id of the runner."
- id: String!
- "The name of the runner."
- name: String!
- "The token."
- token: String!
-}
-"A pipeline for running ci jobs"
-type Pipeline {
- "The configured credential for cloning the pipeline source."
- cloneCredential: CloneCredential
- "The id of the pipeline."
+"A webhook for triggering pipelines"
+type Webhook {
+ "The id of the webhook."
id: String!
- "The name of the pipeline."
- name: String!
- "The polling interval for the pipeline."
- pollInterval: Int!
- "The list of runs for the pipeline."
- runs: [Run!]!
- "The list of secrets for the pipeline."
- secrets: [Secret!]!
- "The url of the pipeline."
- url: String!
- "The list of webhooks for the pipeline."
- webhooks: [Webhook!]!
+ "The secret used to validate the webhook."
+ secret: String!
+ "The format of the webhook."
+ serverType: String!
}
-"A secret available for use inside of a pipeline."
-type Secret {
- "The id of the secret."
+"A credential for authenticating with the pipeline source host."
+type CloneCredential {
+ "The id of the credential."
id: String!
- "The name of the secret."
+ "The name of the credential."
name: String!
- "The secret."
+ "The secret for the credential."
secret: String!
-}
-""
-type Query {
- ""
- CloneCredential(
- "The id of the requested credential."
- id: String!
- ): CloneCredential
- ""
- CloneCredentials: [CloneCredential]!
- ""
- Pipeline(
- "The id of the requested pipeline."
- id: String!
- ): Pipeline
- ""
- Pipelines: [Pipeline]!
- ""
- Runners: [Runner]!
- ""
- Secrets: [Secret]!
+ "The credential type."
+ type: String!
+ "The username to user with the credential."
+ username: String!
}
"A pipeline run"
type Run {
+ "Logs of the top level container build for the run."
+ buildOutput: String
"The id of the run."
id: String!
"The progress status of the run."
diff --git a/widget/pipelineList.go b/widget/pipelineList.go
index f38a92f..cd7aabf 100644
--- a/widget/pipelineList.go
+++ b/widget/pipelineList.go
@@ -42,16 +42,16 @@ func (m pipelineWidgetList) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

case "enter":
if m.list.Index() < len(m.list.Items())-1 {
- //item := m.list.SelectedItem()
- //if item, ok := item.(pipelineListItem); ok {
- // return m, func() tea.Cmd {
- // view, err := createPipelineEditForm(client, item.id)
- // if err != nil {
- // return err
- // }
- // return pipelineWidgetScreenSwitch(view)
- // }
- //}
+ item := m.list.SelectedItem()
+ if item, ok := item.(pipelineListItem); ok {
+ return m, func() tea.Msg {
+ view, err := createPipelineWidgetView(m.client, item.id)
+ if err != nil {
+ return err
+ }
+ return pipelineWidgetScreenSwitch(view)
+ }
+ }
} else {
return m, func() tea.Msg {
view, err := createPipelineCreateForm(m.client, m.list.Width(), m.list.Height())
+83
View File
@@ -0,0 +1,83 @@
package widget
import (
"context"
"fmt"
"io"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"git.ohea.xyz/cursorius/tui/queries"
)
type cloneCredentialListItem struct {
name string
widgetType string
id string
}
type cloneCredentialCreateListItem string
func (i cloneCredentialListItem) FilterValue() string { return "" }
func (i cloneCredentialCreateListItem) FilterValue() string { return "" }
type cloneCredentialListItemDelegate struct{}
func (d cloneCredentialListItemDelegate) Height() int { return 1 }
func (d cloneCredentialListItemDelegate) Spacing() int { return 0 }
func (d cloneCredentialListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d cloneCredentialListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case cloneCredentialListItem:
fn := itemStyle.Render
faintFn := faintItemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
faintFn = faintSelectedItemStyle.Render
}
str := fn(i.name) + faintFn(" ("+i.id+")")
fmt.Fprint(w, str)
case cloneCredentialCreateListItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := string(i)
fmt.Fprint(w, fn(str))
}
}
func CreateCloneCredentialWidget(client graphql.Client) (list.Model, error) {
content := []list.Item{}
getCloneCredentialResp, err := queries.GetCloneCredentials(context.Background(), client)
if err != nil {
return list.Model{}, fmt.Errorf("Could not connect to server: %w", err)
}
if getCloneCredentialResp.CloneCredentials == nil {
for _, cloneCredential := range getCloneCredentialResp.CloneCredentials {
content = append(content, cloneCredentialListItem{
name: cloneCredential.Name,
id: cloneCredential.Id,
})
}
}
content = append(content, cloneCredentialCreateListItem("[Create Clone Credential]"))
model := list.New(content, cloneCredentialListItemDelegate{}, 50, 50)
model.SetShowStatusBar(false)
model.Title = "Clone Credentials"
return model, nil
}
+17
View File
@@ -0,0 +1,17 @@
package widget
import (
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/lipgloss"
)
var (
titleStyle = lipgloss.NewStyle().MarginLeft(2)
itemStyle = lipgloss.NewStyle().PaddingLeft(4)
faintItemStyle = lipgloss.NewStyle().Faint(true)
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
faintSelectedItemStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Faint(true)
paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
)
+53
View File
@@ -0,0 +1,53 @@
package widget
import (
"github.com/Khan/genqlient/graphql"
tea "github.com/charmbracelet/bubbletea"
)
type pipelineWidgetScreenSwitch tea.Model
type pipelineWidget struct {
currentView tea.Model
width int
height int
}
func (m pipelineWidget) Init() tea.Cmd {
return nil
}
func (m pipelineWidget) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = msg.Width
m.height = msg.Height
case pipelineWidgetScreenSwitch:
m.currentView = msg
m.currentView, _ = m.currentView.Update(tea.WindowSizeMsg{
Width: m.width,
Height: m.height,
})
}
var cmd tea.Cmd
m.currentView, cmd = m.currentView.Update(msg)
return m, cmd
}
func (m pipelineWidget) View() string {
return m.currentView.View()
}
func CreatePipelineWidget(client graphql.Client) (tea.Model, error) {
view, err := createPipelineWidgetList(client)
if err != nil {
return pipelineWidget{}, err
}
return pipelineWidget{
currentView: view,
}, nil
}
+164
View File
@@ -0,0 +1,164 @@
package widget
import (
"context"
"fmt"
"io"
"strconv"
"git.ohea.xyz/cursorius/tui/queries"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
)
type pipelineCreateForm struct {
formList list.Model
client graphql.Client
}
func (m pipelineCreateForm) Init() tea.Cmd {
return nil
}
func (m pipelineCreateForm) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc":
return m, func() tea.Msg {
view, err := createPipelineWidgetList(m.client)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
case "enter":
if m.formList.Index() == len(m.formList.Items())-1 {
return m, func() tea.Msg {
name := ""
url := ""
pollIntervalStr := ""
if e, ok := m.formList.Items()[0].(createPipelineItem); ok {
name = e.field.Value()
}
if e, ok := m.formList.Items()[1].(createPipelineItem); ok {
url = e.field.Value()
}
if e, ok := m.formList.Items()[2].(createPipelineItem); ok {
pollIntervalStr = e.field.Value()
}
pollInterval, err := strconv.Atoi(pollIntervalStr)
if err != nil {
pollInterval = 0
}
_, err = queries.CreatePipeline(context.Background(), m.client, name, url, &pollInterval, nil)
if err != nil {
return err
}
view, err := createPipelineWidgetList(m.client)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
}
}
}
var cmd tea.Cmd
m.formList, cmd = m.formList.Update(msg)
items := m.formList.Items()
for i := 0; i < len(items); i++ {
if e, ok := items[i].(createPipelineItem); ok {
if i == m.formList.Index() {
e.field.Focus()
e.field, _ = e.field.Update(msg)
} else {
e.field.Blur()
}
m.formList.SetItem(i, e)
}
}
return m, cmd
}
func Atoi(pollIntervalStr string) {
panic("unimplemented")
}
func (m pipelineCreateForm) View() string {
return m.formList.View()
}
type createPipelineItem struct {
field textinput.Model
}
type createPipelineSubmitItem string
func (i createPipelineItem) FilterValue() string { return "" }
func (i createPipelineSubmitItem) FilterValue() string { return "" }
type createPipelineDelegate struct{}
func (d createPipelineDelegate) Height() int { return 1 }
func (d createPipelineDelegate) Spacing() int { return 0 }
func (d createPipelineDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d createPipelineDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
var str string
switch i := listItem.(type) {
case createPipelineItem:
str = i.field.View()
case createPipelineSubmitItem:
str = string(i)
}
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
fmt.Fprint(w, fn(str))
}
func createPipelineCreateForm(client graphql.Client, width int, height int) (tea.Model, error) {
nameField := textinput.New()
nameField.Focus()
nameField.Width = 20
nameField.Prompt = "Name: "
nameField.Placeholder = "pipeline0"
urlField := textinput.New()
urlField.Prompt = "Url: "
urlField.Placeholder = "https://git.cursorius.ohea/group/repo"
pollIntervalField := textinput.New()
pollIntervalField.Width = 20
pollIntervalField.Prompt = "Poll Interval: "
pollIntervalField.Placeholder = "0 (disable polling)"
items := []list.Item{
createPipelineItem{field: nameField},
createPipelineItem{field: urlField},
createPipelineItem{field: pollIntervalField},
createPipelineSubmitItem("> Submit <"),
}
l := list.New(items, createPipelineDelegate{}, width, height-10)
l.Title = "Create a new pipeline."
l.SetShowStatusBar(false)
l.KeyMap.GoToStart.SetEnabled(false)
l.KeyMap.GoToEnd.SetEnabled(false)
l.KeyMap.Filter.SetEnabled(false)
l.KeyMap.Quit.SetEnabled(false)
return pipelineCreateForm{
formList: l,
client: client,
}, nil
}
+145
View File
@@ -0,0 +1,145 @@
package widget
import (
"context"
"fmt"
"io"
"git.ohea.xyz/cursorius/tui/queries"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
)
type pipelineWidgetList struct {
list list.Model
client graphql.Client
}
func (m pipelineWidgetList) Init() tea.Cmd {
return nil
}
func (m pipelineWidgetList) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.list.SetWidth(msg.Width - 10)
m.list.SetHeight(msg.Height - 10)
case tea.KeyMsg:
switch msg.String() {
case "down":
if m.list.Index() < len(m.list.Items())-1 {
m.list.Select(m.list.Index() + 1)
} else if m.list.Index() == len(m.list.Items())-1 {
m.list.Select(0)
}
case "up":
if m.list.Index() > 0 {
m.list.Select(m.list.Index() - 1)
} else if m.list.Index() == 0 {
m.list.Select(len(m.list.Items()) - 1)
}
case "enter":
if m.list.Index() < len(m.list.Items())-1 {
item := m.list.SelectedItem()
if item, ok := item.(pipelineListItem); ok {
return m, func() tea.Msg {
view, err := createPipelineWidgetView(m.client, item.id)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
}
} else {
return m, func() tea.Msg {
view, err := createPipelineCreateForm(m.client, m.list.Width(), m.list.Height())
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
}
}
}
return m, nil
}
func (m pipelineWidgetList) View() string {
return m.list.View()
}
type pipelineListItem struct {
name string
id string
}
type pipelineCreateListItem string
func (i pipelineListItem) FilterValue() string { return "" }
func (i pipelineCreateListItem) FilterValue() string { return "" }
type pipelineListItemDelegate struct{}
func (d pipelineListItemDelegate) Height() int { return 1 }
func (d pipelineListItemDelegate) Spacing() int { return 0 }
func (d pipelineListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d pipelineListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case pipelineListItem:
fn := itemStyle.Render
faintFn := faintItemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
faintFn = faintSelectedItemStyle.Render
}
str := fn(i.name) + faintFn(" ("+i.id+")")
fmt.Fprint(w, str)
case pipelineCreateListItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := string(i)
fmt.Fprint(w, fn(str))
}
}
func createPipelineWidgetList(client graphql.Client) (tea.Model, error) {
getPipelinesResp, err := queries.GetPipelines(context.Background(), client)
if err != nil {
return pipelineWidget{}, fmt.Errorf("Could not connect to server: %w", err)
}
var content []list.Item
if getPipelinesResp.Pipelines != nil {
for _, pipeline := range getPipelinesResp.Pipelines {
if pipeline != nil {
content = append(content, pipelineListItem{
name: pipeline.Name,
id: pipeline.Id,
})
}
}
}
content = append(content, pipelineCreateListItem("[Create Pipeline]"))
pipelineList := list.New(content, pipelineListItemDelegate{}, 0, 0)
pipelineList.SetShowStatusBar(false)
pipelineList.Title = "Pipelines"
return pipelineWidgetList{
list: pipelineList,
client: client,
}, nil
}
+263
View File
@@ -0,0 +1,263 @@
package widget
import (
"context"
"fmt"
"io"
"git.ohea.xyz/cursorius/tui/queries"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
)
type pipelineWidgetViewPage int
const (
topLevel pipelineWidgetViewPage = 0
viewRun = 1
viewRunBuildOutput = 2
viewRunStdout = 3
viewRunStderr = 4
)
type pipelineWidgetView struct {
client graphql.Client
page pipelineWidgetViewPage
pipeline queries.GetPipelinePipeline
runsList list.Model
viewRunSelector list.Model
viewRunBuildOutputPager viewport.Model
viewRunStdoutPager viewport.Model
viewRunStderrPager viewport.Model
}
func (m pipelineWidgetView) Init() tea.Cmd {
return nil
}
func (m pipelineWidgetView) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.runsList.SetWidth(msg.Width - 20)
m.runsList.SetHeight(msg.Height - 20)
case tea.KeyMsg:
switch msg.String() {
case "r":
return m, func() tea.Msg {
view, err := createPipelineWidgetView(m.client, m.pipeline.Id)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
case "backspace":
switch m.page {
case topLevel:
return m, func() tea.Msg {
view, err := createPipelineWidgetList(m.client)
if err != nil {
return err
}
return pipelineWidgetScreenSwitch(view)
}
case viewRun:
m.page = topLevel
case viewRunBuildOutput:
m.page = viewRun
case viewRunStderr:
m.page = viewRun
case viewRunStdout:
m.page = viewRun
}
case "enter":
switch m.page {
case topLevel:
run := m.pipeline.Runs[m.runsList.Index()]
content := []list.Item{
pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("ID: %v", run.Id)),
}
if run.InProgress != nil {
content = append(content, pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("In Progress: %v", *run.InProgress)))
} else {
content = append(content, pipelineWidgetViewRunsSelectorItem("In Progress: null"))
}
if run.Result != nil {
content = append(content, pipelineWidgetViewRunsSelectorItem(fmt.Sprintf("Result: %v", *run.Result)))
} else {
content = append(content, pipelineWidgetViewRunsSelectorItem("Result: null"))
}
content = append(content, pipelineWidgetViewRunsSelectorItem("View Build Output"))
content = append(content, pipelineWidgetViewRunsSelectorItem("View Stdout"))
content = append(content, pipelineWidgetViewRunsSelectorItem("View Stderr"))
runOutputList := list.New(content, pipelineWigetViewRunsSelectorItemDelegate{}, m.runsList.Width(), m.runsList.Height())
runOutputList.SetShowStatusBar(false)
runOutputList.Title = "View Run"
runOutputList.DisableQuitKeybindings()
m.viewRunSelector = runOutputList
m.page = viewRun
case viewRun:
run := m.pipeline.Runs[m.runsList.Index()]
switch m.viewRunSelector.Index() {
case 3:
if run.BuildOutput == nil {
break
}
m.viewRunBuildOutputPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunBuildOutputPager.SetContent(*run.BuildOutput)
m.page = viewRunBuildOutput
case 4:
if run.Stdout == nil {
break
}
m.viewRunStdoutPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunStdoutPager.SetContent(*run.Stdout)
m.page = viewRunStdout
case 5:
if run.Stderr == nil {
break
}
m.viewRunStderrPager = viewport.New(m.runsList.Width(), m.runsList.Height())
m.viewRunStderrPager.SetContent(*run.Stderr)
m.page = viewRunStderr
}
}
}
}
var cmd tea.Cmd
switch m.page {
case topLevel:
m.runsList, cmd = m.runsList.Update(msg)
case viewRun:
m.viewRunSelector, cmd = m.viewRunSelector.Update(msg)
case viewRunBuildOutput:
m.viewRunBuildOutputPager, cmd = m.viewRunBuildOutputPager.Update(msg)
case viewRunStdout:
m.viewRunStdoutPager, cmd = m.viewRunStdoutPager.Update(msg)
case viewRunStderr:
m.viewRunStderrPager, cmd = m.viewRunStderrPager.Update(msg)
}
return m, cmd
}
func (m pipelineWidgetView) View() string {
s := ""
switch m.page {
case topLevel:
s += fmt.Sprintf("Pipeline: %v\n\n", m.pipeline.Name)
s += fmt.Sprintf("Id: %v\n", m.pipeline.Id)
s += fmt.Sprintf("Url: %v\n", m.pipeline.Url)
s += fmt.Sprintf("Poll Interval: %v\n", m.pipeline.PollInterval)
if m.pipeline.CloneCredential != nil {
s += fmt.Sprintf("Clone Credential: %v (%v)\n\n", m.pipeline.CloneCredential.Name, m.pipeline.CloneCredential.Type)
} else {
s += fmt.Sprintf("Clone Credential: None\n\n")
}
s += m.runsList.View()
case viewRun:
s += m.viewRunSelector.View()
case viewRunBuildOutput:
s += m.viewRunBuildOutputPager.View()
case viewRunStdout:
s += m.viewRunStdoutPager.View()
case viewRunStderr:
s += m.viewRunStderrPager.View()
}
return s
}
func createPipelineWidgetView(client graphql.Client, id string) (tea.Model, error) {
getPipelineResp, err := queries.GetPipeline(context.Background(), client, id)
if err != nil {
return nil, err
}
if getPipelineResp.Pipeline == nil {
return nil, fmt.Errorf("Server did not give us a pipeline")
}
var content []list.Item
for _, run := range getPipelineResp.Pipeline.Runs {
content = append(content, pipelineWidgetViewRunsItem{
id: run.Id,
})
}
runsList := list.New(content, pipelineWigetViewRunsItemDelegate{}, 0, 0)
runsList.SetShowStatusBar(false)
runsList.Title = "Runs"
return pipelineWidgetView{
client: client,
page: topLevel,
pipeline: *getPipelineResp.Pipeline,
runsList: runsList,
}, nil
}
type pipelineWidgetViewRunsItem struct {
id string
}
func (i pipelineWidgetViewRunsItem) FilterValue() string { return "" }
type pipelineWigetViewRunsItemDelegate struct{}
func (d pipelineWigetViewRunsItemDelegate) Height() int { return 1 }
func (d pipelineWigetViewRunsItemDelegate) Spacing() int { return 0 }
func (d pipelineWigetViewRunsItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d pipelineWigetViewRunsItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case pipelineWidgetViewRunsItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := fn(i.id)
fmt.Fprint(w, str)
}
}
type pipelineWidgetViewRunsSelectorItem string
func (i pipelineWidgetViewRunsSelectorItem) FilterValue() string { return "" }
type pipelineWigetViewRunsSelectorItemDelegate struct{}
func (d pipelineWigetViewRunsSelectorItemDelegate) Height() int { return 1 }
func (d pipelineWigetViewRunsSelectorItemDelegate) Spacing() int { return 0 }
func (d pipelineWigetViewRunsSelectorItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd {
return nil
}
func (d pipelineWigetViewRunsSelectorItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case pipelineWidgetViewRunsSelectorItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := fn(string(i))
fmt.Fprint(w, str)
}
}
+79
View File
@@ -0,0 +1,79 @@
package widget
import (
"context"
"fmt"
"io"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"git.ohea.xyz/cursorius/tui/queries"
)
type runnerListItem struct {
name string
id string
}
type runnerCreateListItem string
func (i runnerListItem) FilterValue() string { return "" }
func (i runnerCreateListItem) FilterValue() string { return "" }
type runnerListItemDelegate struct{}
func (d runnerListItemDelegate) Height() int { return 1 }
func (d runnerListItemDelegate) Spacing() int { return 0 }
func (d runnerListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d runnerListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case runnerListItem:
fn := itemStyle.Render
faintFn := faintItemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
faintFn = faintSelectedItemStyle.Render
}
str := fn(i.name) + faintFn(" ("+i.id+")")
fmt.Fprint(w, str)
case runnerCreateListItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := string(i)
fmt.Fprint(w, fn(str))
}
}
func CreateRunnerWidget(client graphql.Client) (list.Model, error) {
content := []list.Item{}
getRunnerResp, err := queries.GetRunners(context.Background(), client)
if err != nil {
return list.Model{}, fmt.Errorf("Could not connect to server: %w", err)
}
if getRunnerResp.Runners == nil {
for _, cloneCredential := range getRunnerResp.Runners {
content = append(content, runnerCreateListItem(cloneCredential.Name))
}
}
content = append(content, runnerCreateListItem("[Create Runner]"))
model := list.New(content, runnerListItemDelegate{}, 50, 50)
model.SetShowStatusBar(false)
model.Title = "Runners"
return model, nil
}
+82
View File
@@ -0,0 +1,82 @@
package widget
import (
"context"
"fmt"
"io"
"github.com/Khan/genqlient/graphql"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"git.ohea.xyz/cursorius/tui/queries"
)
type secretListItem struct {
name string
id string
}
type secretCreateListItem string
func (i secretListItem) FilterValue() string { return "" }
func (i secretCreateListItem) FilterValue() string { return "" }
type secretListItemDelegate struct{}
func (d secretListItemDelegate) Height() int { return 1 }
func (d secretListItemDelegate) Spacing() int { return 0 }
func (d secretListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
func (d secretListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
switch i := listItem.(type) {
case secretListItem:
fn := itemStyle.Render
faintFn := faintItemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
faintFn = faintSelectedItemStyle.Render
}
str := fn(i.name) + faintFn(" ("+i.id+")")
fmt.Fprint(w, str)
case secretCreateListItem:
fn := itemStyle.Render
if index == m.Index() {
fn = func(s string) string {
return selectedItemStyle.Render("> " + s)
}
}
str := string(i)
fmt.Fprint(w, fn(str))
}
}
func CreateSecretWidget(client graphql.Client) (list.Model, error) {
content := []list.Item{}
getSecretResp, err := queries.GetSecrets(context.Background(), client)
if err != nil {
return list.Model{}, fmt.Errorf("Could not connect to server: %w", err)
}
if getSecretResp.Secrets == nil {
for _, secret := range getSecretResp.Secrets {
content = append(content, secretListItem{
name: secret.Name,
id: secret.Id,
})
}
}
content = append(content, secretCreateListItem("[Create Secret]"))
model := list.New(content, secretListItemDelegate{}, 50, 50)
model.SetShowStatusBar(false)
model.Title = "Secrets"
return model, nil
}