Merge branch 'master' into bbserver-cleanup
14
.drone.yml
|
@ -1,23 +1,21 @@
|
|||
workspace:
|
||||
base: /drone
|
||||
base: /go
|
||||
path: src/github.com/drone/drone
|
||||
|
||||
pipeline:
|
||||
test:
|
||||
image: drone/golang:1.5
|
||||
backend:
|
||||
image: golang:1.6
|
||||
environment:
|
||||
- GO15VENDOREXPERIMENT=1
|
||||
- GOPATH=/drone
|
||||
commands:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make deps gen
|
||||
- make test test_postgres test_mysql
|
||||
|
||||
build:
|
||||
image: drone/golang:1.5
|
||||
compile:
|
||||
image: golang:1.6
|
||||
environment:
|
||||
- GO15VENDOREXPERIMENT=1
|
||||
- GOPATH=/drone
|
||||
- GOPATH=/go
|
||||
commands:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make build
|
||||
|
|
|
@ -1 +1 @@
|
|||
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9kcm9uZQogIHBhdGg6IHNyYy9naXRodWIuY29tL2Ryb25lL2Ryb25lCgpwaXBlbGluZToKICB0ZXN0OgogICAgaW1hZ2U6IGRyb25lL2dvbGFuZzoxLjUKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgICAgLSBHT1BBVEg9L2Ryb25lCiAgICBjb21tYW5kczoKICAgICAgLSBleHBvcnQgUEFUSD0kUEFUSDokR09QQVRIL2JpbgogICAgICAtIG1ha2UgZGVwcyBnZW4KICAgICAgLSBtYWtlIHRlc3QgdGVzdF9wb3N0Z3JlcyB0ZXN0X215c3FsCgogIGJ1aWxkOgogICAgaW1hZ2U6IGRyb25lL2dvbGFuZzoxLjUKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgICAgLSBHT1BBVEg9L2Ryb25lCiAgICBjb21tYW5kczoKICAgICAgLSBleHBvcnQgUEFUSD0kUEFUSDokR09QQVRIL2JpbgogICAgICAtIG1ha2UgYnVpbGQKICAgIHdoZW46CiAgICAgIGV2ZW50OiBwdXNoCgogIHB1Ymxpc2g6CiAgICBpbWFnZTogczMKICAgIGFjbDogcHVibGljLXJlYWQKICAgIGJ1Y2tldDogZG93bmxvYWRzLmRyb25lLmlvCiAgICBzb3VyY2U6IHJlbGVhc2UvKiovKi4qCiAgICB3aGVuOgogICAgICBldmVudDogcHVzaAogICAgICBicmFuY2g6IG1hc3RlcgoKICBkb2NrZXI6CiAgICByZXBvOiBkcm9uZS9kcm9uZQogICAgdGFnOiBbICIwLjUuMCIsICIwLjUiIF0KICAgIHN0b3JhZ2VfZHJpdmVyOiBvdmVybGF5CiAgICB3aGVuOgogICAgICBicmFuY2g6IG1hc3RlcgogICAgICBldmVudDogcHVzaAoKc2VydmljZXM6CiAgcG9zdGdyZXM6CiAgICBpbWFnZTogcG9zdGdyZXM6OS40LjUKICAgIGVudmlyb25tZW50OgogICAgICAtIFBPU1RHUkVTX1VTRVI9cG9zdGdyZXMKICBteXNxbDoKICAgIGltYWdlOiBteXNxbDo1LjYuMjcKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX0RBVEFCQVNFPXRlc3QKICAgICAgLSBNWVNRTF9BTExPV19FTVBUWV9QQVNTV09SRD15ZXMK.PFyNsvPRNRtL_9Tlgsqa0IDMIgzUrlk53eV4QJjZ3hU
|
||||
eyJhbGciOiJIUzI1NiJ9.d29ya3NwYWNlOgogIGJhc2U6IC9nbwogIHBhdGg6IHNyYy9naXRodWIuY29tL2Ryb25lL2Ryb25lCgpwaXBlbGluZToKICBiYWNrZW5kOgogICAgaW1hZ2U6IGdvbGFuZzoxLjYKICAgIGVudmlyb25tZW50OgogICAgICAtIEdPMTVWRU5ET1JFWFBFUklNRU5UPTEKICAgIGNvbW1hbmRzOgogICAgICAtIG1ha2UgZGVwcyBnZW4KICAgICAgLSBtYWtlIHRlc3QgdGVzdF9wb3N0Z3JlcyB0ZXN0X215c3FsCgogIGNvbXBpbGU6CiAgICBpbWFnZTogZ29sYW5nOjEuNgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gR08xNVZFTkRPUkVYUEVSSU1FTlQ9MQogICAgICAtIEdPUEFUSD0vZ28KICAgIGNvbW1hbmRzOgogICAgICAtIGV4cG9ydCBQQVRIPSRQQVRIOiRHT1BBVEgvYmluCiAgICAgIC0gbWFrZSBidWlsZAogICAgd2hlbjoKICAgICAgZXZlbnQ6IHB1c2gKCiAgcHVibGlzaDoKICAgIGltYWdlOiBzMwogICAgYWNsOiBwdWJsaWMtcmVhZAogICAgYnVja2V0OiBkb3dubG9hZHMuZHJvbmUuaW8KICAgIHNvdXJjZTogcmVsZWFzZS8qKi8qLioKICAgIHdoZW46CiAgICAgIGV2ZW50OiBwdXNoCiAgICAgIGJyYW5jaDogbWFzdGVyCgogIGRvY2tlcjoKICAgIHJlcG86IGRyb25lL2Ryb25lCiAgICB0YWc6IFsgIjAuNS4wIiwgIjAuNSIgXQogICAgc3RvcmFnZV9kcml2ZXI6IG92ZXJsYXkKICAgIHdoZW46CiAgICAgIGJyYW5jaDogbWFzdGVyCiAgICAgIGV2ZW50OiBwdXNoCgpzZXJ2aWNlczoKICBwb3N0Z3JlczoKICAgIGltYWdlOiBwb3N0Z3Jlczo5LjQuNQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gUE9TVEdSRVNfVVNFUj1wb3N0Z3JlcwogIG15c3FsOgogICAgaW1hZ2U6IG15c3FsOjUuNi4yNwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gTVlTUUxfREFUQUJBU0U9dGVzdAogICAgICAtIE1ZU1FMX0FMTE9XX0VNUFRZX1BBU1NXT1JEPXllcwo.kQIwqIgs7PnoKIGmzJ6hlbWTbV5zK0w4HVWsux79P3s
|
3
.gitignore
vendored
|
@ -1,7 +1,6 @@
|
|||
drone/drone
|
||||
*.sqlite
|
||||
*_gen.go
|
||||
*.html
|
||||
#*.css
|
||||
*.txt
|
||||
*.zip
|
||||
|
@ -13,6 +12,8 @@ drone/drone
|
|||
temp/
|
||||
release/
|
||||
|
||||
server/frontend/bower_components
|
||||
server/frontend/build
|
||||
server/swagger/files/*.json
|
||||
|
||||
# vendored repositories that we don't actually need
|
||||
|
|
28
Makefile
|
@ -10,22 +10,20 @@ endif
|
|||
|
||||
all: gen build_static
|
||||
|
||||
deps:
|
||||
deps: deps_backend deps_frontend
|
||||
|
||||
deps_frontend:
|
||||
go get -u github.com/drone/drone-ui/dist
|
||||
|
||||
deps_backend:
|
||||
go get -u golang.org/x/tools/cmd/cover
|
||||
go get -u github.com/eknkc/amber/...
|
||||
go get -u github.com/eknkc/amber
|
||||
go get -u github.com/jteeuwen/go-bindata/...
|
||||
go get -u github.com/elazarl/go-bindata-assetfs/...
|
||||
go get -u github.com/dchest/jsmin
|
||||
go get -u github.com/franela/goblin
|
||||
|
||||
gen: gen_static gen_template gen_migrations
|
||||
|
||||
gen_static:
|
||||
go generate github.com/drone/drone/static
|
||||
gen: gen_template gen_migrations
|
||||
|
||||
gen_template:
|
||||
go generate github.com/drone/drone/template
|
||||
go generate github.com/drone/drone/server/template
|
||||
|
||||
gen_migrations:
|
||||
go generate github.com/drone/drone/store/datastore/ddl
|
||||
|
@ -58,11 +56,11 @@ build_cross:
|
|||
|
||||
# TODO this is getting moved to a shell script, do not alter
|
||||
build_tar:
|
||||
tar -cvzf release/linux/amd64/drone.tar.gz release/linux/amd64/drone
|
||||
tar -cvzf release/linux/arm64/drone.tar.gz release/linux/arm64/drone
|
||||
tar -cvzf release/linux/arm/drone.tar.gz release/linux/arm/drone
|
||||
tar -cvzf release/windows/amd64/drone.tar.gz release/windows/amd64/drone
|
||||
tar -cvzf release/darwin/amd64/drone.tar.gz release/darwin/amd64/drone
|
||||
tar -cvzf release/linux/amd64/drone.tar.gz -C release/linux/amd64 drone
|
||||
tar -cvzf release/linux/arm64/drone.tar.gz -C release/linux/arm64 drone
|
||||
tar -cvzf release/linux/arm/drone.tar.gz -C release/linux/arm drone
|
||||
tar -cvzf release/windows/amd64/drone.tar.gz -C release/windows/amd64 drone
|
||||
tar -cvzf release/darwin/amd64/drone.tar.gz -C release/darwin/amd64 drone
|
||||
|
||||
# TODO this is getting moved to a shell script, do not alter
|
||||
build_sha:
|
||||
|
|
|
@ -22,7 +22,7 @@ Drone documentation is organized into several categories:
|
|||
|
||||
If you are using the 0.5 unstable release (master branch) please see the updated documentation:
|
||||
|
||||
* [Setup Guide](http://readme.drone.io/0.5/manage/server/)
|
||||
* [Setup Guide](http://readme.drone.io/0.5/installation/server/)
|
||||
* [Build Guide](http://readme.drone.io/0.5/usage/overview/)
|
||||
|
||||
### Community, Help
|
||||
|
|
|
@ -2,8 +2,10 @@ package build
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/drone/drone/yaml"
|
||||
)
|
||||
|
||||
|
@ -48,6 +50,12 @@ func (p *Pipeline) Next() <-chan error {
|
|||
// Exec executes the current step.
|
||||
func (p *Pipeline) Exec() {
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Errorln("recover executing build step", r)
|
||||
}
|
||||
}()
|
||||
|
||||
err := p.exec(p.head.Container)
|
||||
if err != nil {
|
||||
p.err = err
|
||||
|
@ -119,6 +127,11 @@ func (p *Pipeline) step() {
|
|||
// close closes open channels and signals the pipeline is done.
|
||||
func (p *Pipeline) close(err error) {
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Errorln("recover closing the pipeline", r)
|
||||
}
|
||||
}()
|
||||
p.done <- err
|
||||
}()
|
||||
}
|
||||
|
@ -131,6 +144,12 @@ func (p *Pipeline) exec(c *yaml.Container) error {
|
|||
p.containers = append(p.containers, name)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Errorln("recover writing build output", r)
|
||||
}
|
||||
}()
|
||||
|
||||
rc, rerr := p.engine.ContainerLogs(name)
|
||||
if rerr != nil {
|
||||
return
|
||||
|
@ -165,5 +184,19 @@ func (p *Pipeline) exec(c *yaml.Container) error {
|
|||
} else if state.ExitCode != 0 {
|
||||
return &ExitError{c.Name, state.ExitCode}
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Errorln("recover writing exit code to output", r)
|
||||
}
|
||||
}()
|
||||
|
||||
p.pipe <- &Line{
|
||||
Proc: c.Name,
|
||||
Type: ExitCodeLine,
|
||||
Out: strconv.Itoa(state.ExitCode),
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,14 @@ package build
|
|||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
StdoutLine int = iota
|
||||
StderrLine
|
||||
ExitCodeLine
|
||||
MetadataLine
|
||||
ProgressLine
|
||||
)
|
||||
|
||||
// Line is a line of console output.
|
||||
type Line struct {
|
||||
Proc string `json:"proc,omitempty"`
|
||||
|
@ -12,7 +20,12 @@ type Line struct {
|
|||
}
|
||||
|
||||
func (l *Line) String() string {
|
||||
return fmt.Sprintf("[%s:L%v:%vs] %s", l.Proc, l.Pos, l.Time, l.Out)
|
||||
switch l.Type {
|
||||
case ExitCodeLine:
|
||||
return fmt.Sprintf("[%s] exit code %s", l.Proc, l.Out)
|
||||
default:
|
||||
return fmt.Sprintf("[%s:L%v:%vs] %s", l.Proc, l.Pos, l.Time, l.Out)
|
||||
}
|
||||
}
|
||||
|
||||
// State defines the state of the container.
|
||||
|
|
14
cache/helper.go
vendored
|
@ -53,6 +53,20 @@ func GetRepos(c context.Context, user *model.User) ([]*model.RepoLite, error) {
|
|||
return repos, nil
|
||||
}
|
||||
|
||||
// GetRepoMap returns the list of user repositories from the cache
|
||||
// associated with the current context in a map structure.
|
||||
func GetRepoMap(c context.Context, user *model.User) (map[string]bool, error) {
|
||||
repos, err := GetRepos(c, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repom := map[string]bool{}
|
||||
for _, repo := range repos {
|
||||
repom[repo.FullName] = true
|
||||
}
|
||||
return repom, nil
|
||||
}
|
||||
|
||||
// DeleteRepos evicts the cached user repositories from the cache associated
|
||||
// with the current context.
|
||||
func DeleteRepos(c context.Context, user *model.User) error {
|
||||
|
|
|
@ -43,12 +43,18 @@ type Client interface {
|
|||
// RepoPatch updates a repository.
|
||||
RepoPatch(*model.Repo) (*model.Repo, error)
|
||||
|
||||
// RepoChown updates a repository owner.
|
||||
RepoChown(string, string) (*model.Repo, error)
|
||||
|
||||
// RepoDel deletes a repository.
|
||||
RepoDel(string, string) error
|
||||
|
||||
// Sign returns a cryptographic signature for the input string.
|
||||
Sign(string, string, []byte) ([]byte, error)
|
||||
|
||||
// SecretList returns a list of all repository secrets.
|
||||
SecretList(string, string) ([]*model.Secret, error)
|
||||
|
||||
// SecretPost create or updates a repository secret.
|
||||
SecretPost(string, string, *model.Secret) error
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ const (
|
|||
pathFeed = "%s/api/user/feed"
|
||||
pathRepos = "%s/api/user/repos"
|
||||
pathRepo = "%s/api/repos/%s/%s"
|
||||
pathChown = "%s/api/repos/%s/%s/chown"
|
||||
pathEncrypt = "%s/api/repos/%s/%s/encrypt"
|
||||
pathBuilds = "%s/api/repos/%s/%s/builds"
|
||||
pathBuild = "%s/api/repos/%s/%s/builds/%v"
|
||||
|
@ -153,6 +154,14 @@ func (c *client) RepoPost(owner string, name string) (*model.Repo, error) {
|
|||
return out, err
|
||||
}
|
||||
|
||||
// RepoChow updates a repository owner.
|
||||
func (c *client) RepoChown(owner string, name string) (*model.Repo, error) {
|
||||
out := new(model.Repo)
|
||||
uri := fmt.Sprintf(pathChown, c.base, owner, name)
|
||||
err := c.post(uri, nil, out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// RepoPatch updates a repository.
|
||||
func (c *client) RepoPatch(in *model.Repo) (*model.Repo, error) {
|
||||
out := new(model.Repo)
|
||||
|
@ -247,6 +256,14 @@ func (c *client) Deploy(owner, name string, num int, env string) (*model.Build,
|
|||
return out, err
|
||||
}
|
||||
|
||||
// SecretList returns a list of a repository secrets.
|
||||
func (c *client) SecretList(owner, name string) ([]*model.Secret, error) {
|
||||
var out []*model.Secret
|
||||
uri := fmt.Sprintf(pathSecrets, c.base, owner, name)
|
||||
err := c.get(uri, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SecretPost create or updates a repository secret.
|
||||
func (c *client) SecretPost(owner, name string, secret *model.Secret) error {
|
||||
uri := fmt.Sprintf(pathSecrets, c.base, owner, name)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
/etc/init/drone.conf
|
||||
/etc/drone/dronerc
|
|
@ -1,7 +0,0 @@
|
|||
Package: drone
|
||||
Version: 0.4
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
Maintainer: Brad Rydzewski <brad@drone.io>
|
||||
Description: Drone continuous integration server
|
|
@ -1,24 +0,0 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
abort-upgrade|abort-remove|abort-deconfigure|configure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Starting drone ..."
|
||||
if [ -f /etc/init/drone.conf ]; then
|
||||
if pidof /usr/local/bin/drone >/dev/null; then
|
||||
service drone stop || exit $?
|
||||
fi
|
||||
service drone start && echo "Drone started."
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
case "$1" in
|
||||
remove|remove-in-favour|deconfigure|deconfigure-in-favour)
|
||||
if [ -f /etc/init/drone.conf ]; then
|
||||
echo "Stopping drone ..."
|
||||
service drone stop || exit $?
|
||||
echo "Drone Stopped."
|
||||
fi
|
||||
;;
|
||||
|
||||
upgrade|failed-upgrade)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "prerm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
|
@ -1,31 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# server configuration
|
||||
|
||||
SERVER_ADDR=":80"
|
||||
#SERVER_CERT=""
|
||||
#SERVER_KEY=""
|
||||
|
||||
# database configuration
|
||||
|
||||
DATABASE_DRIVER="sqlite3"
|
||||
DATABASE_CONFIG="/var/lib/drone/drone.sqlite"
|
||||
|
||||
# remote configuration
|
||||
|
||||
CLIENT="" # oauth2 client. REQUIRED
|
||||
SECRET="" # oauth2 secret. REQUIRED
|
||||
|
||||
REMOTE_DRIVER="github"
|
||||
REMOTE_CONFIG="https://github.com?client_id=$CLIENT&client_secret=$SECRET"
|
||||
|
||||
# docker configuration
|
||||
|
||||
DOCKER_HOST="unix:///var/run/docker.sock"
|
||||
#DOCKER_CERT=""
|
||||
#DOCKER_KEY=""
|
||||
#DOCKER_CA=""
|
||||
|
||||
# plugin configuration
|
||||
|
||||
PLUGIN_FILTER="plugins/*"
|
|
@ -1,12 +0,0 @@
|
|||
start on (filesystem and net-device-up)
|
||||
|
||||
chdir /var/lib/drone
|
||||
console log
|
||||
|
||||
script
|
||||
set -a
|
||||
if [ -f /etc/drone/dronerc ]; then
|
||||
. /etc/drone/dronerc
|
||||
fi
|
||||
/usr/local/bin/drone
|
||||
end script
|
|
@ -1,19 +0,0 @@
|
|||
# /etc/nsswitch.conf
|
||||
#
|
||||
# Example configuration of GNU Name Service Switch functionality.
|
||||
# If you have the `glibc-doc-reference' and `info' packages installed, try:
|
||||
# `info libc "Name Service Switch"' for information about this file.
|
||||
|
||||
passwd: compat
|
||||
group: compat
|
||||
shadow: compat
|
||||
|
||||
hosts: files dns
|
||||
networks: files
|
||||
|
||||
protocols: files
|
||||
services: files
|
||||
ethers: files
|
||||
rpc: files
|
||||
|
||||
netgroup: nis
|
|
@ -1,6 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
// This program converts amber templates to standard
|
||||
// Go template files.
|
||||
|
||||
package main
|
|
@ -1,60 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
// This program minifies JavaScript files
|
||||
// $ go run generate-js.go -dir scripts/ -out scripts/drone.min.js
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/dchest/jsmin"
|
||||
)
|
||||
|
||||
var (
|
||||
dir = flag.String("dir", "scripts/", "")
|
||||
out = flag.String("o", "scripts/drone.min.js", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
// walk the directory tree and write all
|
||||
// javascript files to the buffer.
|
||||
filepath.Walk(*dir, func(path string, info os.FileInfo, err error) error {
|
||||
if filepath.Ext(path) != ".js" {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// write the file name to the minified output
|
||||
fmt.Fprintf(&buf, "// %s\n", path)
|
||||
|
||||
// copy the file to the buffer
|
||||
_, err = io.Copy(&buf, f)
|
||||
return err
|
||||
})
|
||||
|
||||
// minifies the javascript
|
||||
data, err := jsmin.Minify(buf.Bytes())
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// write the minified output
|
||||
ioutil.WriteFile(*out, data, 0700)
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd /tmp
|
||||
|
||||
# cleanup previously downloaded and unpacked files.
|
||||
rm -rf libsass
|
||||
rm -rf sassc
|
||||
|
||||
# download the latest build of sassc
|
||||
git clone --depth=1 git://github.com/sass/libsass.git
|
||||
git clone --depth=1 git://github.com/sass/sassc.git
|
||||
|
||||
export SASS_LIBSASS_PATH=/tmp/libsass
|
||||
|
||||
# build the sassc binary
|
||||
cd sassc
|
||||
make
|
||||
|
||||
# isntall the sassc binary
|
||||
install -t /usr/local/bin bin/sassc
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd /tmp
|
||||
|
||||
# cleanup previously downloaded and unpacked files.
|
||||
rm -rf sqlite-autoconf-3081101.tar.gz
|
||||
rm -rf sqlite-autoconf-3081101
|
||||
|
||||
# download sqlite
|
||||
curl -O https://www.sqlite.org/2015/sqlite-autoconf-3081101.tar.gz
|
||||
tar xzf sqlite-autoconf-3081101.tar.gz
|
||||
|
||||
# build and install
|
||||
cd sqlite-autoconf-3081101
|
||||
./configure -prefix=/scratch/usr/local
|
||||
make
|
||||
make install
|
|
@ -8,5 +8,6 @@ var secretCmd = cli.Command{
|
|||
Subcommands: []cli.Command{
|
||||
secretAddCmd,
|
||||
secretRemoveCmd,
|
||||
secretListCmd,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1 +1,87 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var secretListCmd = cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "list all secrets",
|
||||
Action: func(c *cli.Context) {
|
||||
if err := secretList(c); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "format output",
|
||||
Value: tmplSecretList,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "image",
|
||||
Usage: "filter by image",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "event",
|
||||
Usage: "filter by event",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretList(c *cli.Context) error {
|
||||
owner, name, err := parseRepo(c.Args().First())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := newClient(c)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secrets, err := client.SecretList(owner, name)
|
||||
|
||||
if err != nil || len(secrets) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(c.String("format") + "\n")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, secret := range secrets {
|
||||
if c.String("image") != "" && !stringInSlice(c.String("image"), secret.Images) {
|
||||
continue
|
||||
}
|
||||
|
||||
if c.String("event") != "" && !stringInSlice(c.String("event"), secret.Events) {
|
||||
continue
|
||||
}
|
||||
|
||||
tmpl.Execute(os.Stdout, secret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// template for secret list items
|
||||
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
||||
Images: {{ list .Images }}
|
||||
Events: {{ list .Events }}
|
||||
`
|
||||
|
||||
var secretFuncMap = template.FuncMap{
|
||||
"list": func(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
},
|
||||
}
|
||||
|
|
|
@ -51,3 +51,13 @@ func readInput(in string) ([]byte, error) {
|
|||
}
|
||||
return ioutil.ReadFile(in)
|
||||
}
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -55,3 +55,12 @@ func (s *Secret) MatchEvent(event string) bool {
|
|||
func (s *Secret) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Secret) Clone() *Secret {
|
||||
return &Secret{
|
||||
ID: s.ID,
|
||||
Name: s.Name,
|
||||
Images: s.Images,
|
||||
Events: s.Events,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,15 +120,23 @@ func fixMalformedAvatar(url string) string {
|
|||
}
|
||||
|
||||
// expandAvatar is a helper function that converts a relative avatar URL to the
|
||||
// abosolute url.
|
||||
// absolute url.
|
||||
func expandAvatar(repo, rawurl string) string {
|
||||
if !strings.HasPrefix(rawurl, "/avatars/") {
|
||||
return rawurl
|
||||
}
|
||||
url, err := url.Parse(repo)
|
||||
aurl, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
return rawurl
|
||||
}
|
||||
url.Path = rawurl
|
||||
return url.String()
|
||||
if aurl.IsAbs() {
|
||||
// Url is already absolute
|
||||
return aurl.String()
|
||||
}
|
||||
|
||||
// Resolve to base
|
||||
burl, err := url.Parse(repo)
|
||||
if err != nil {
|
||||
return rawurl
|
||||
}
|
||||
aurl = burl.ResolveReference(aurl)
|
||||
|
||||
return aurl.String()
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func Test_parse(t *testing.T) {
|
|||
g.Assert(build.Link).Equal(hook.Compare)
|
||||
g.Assert(build.Branch).Equal("master")
|
||||
g.Assert(build.Message).Equal(hook.Commits[0].Message)
|
||||
g.Assert(build.Avatar).Equal("//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
|
||||
g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87")
|
||||
g.Assert(build.Author).Equal(hook.Sender.Login)
|
||||
|
||||
})
|
||||
|
@ -92,7 +92,7 @@ func Test_parse(t *testing.T) {
|
|||
FullName: "gophers/hello-world",
|
||||
Owner: gogs.User{
|
||||
UserName: "gordon",
|
||||
AvatarUrl: "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
AvatarUrl: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
},
|
||||
CloneUrl: "http://gogs.golang.org/gophers/hello-world.git",
|
||||
HtmlUrl: "http://gogs.golang.org/gophers/hello-world",
|
||||
|
@ -114,7 +114,7 @@ func Test_parse(t *testing.T) {
|
|||
FullName: "gophers/hello-world",
|
||||
Owner: gogs.User{
|
||||
UserName: "gordon",
|
||||
AvatarUrl: "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
AvatarUrl: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
},
|
||||
}
|
||||
repo := toRepoLite(&from)
|
||||
|
@ -165,7 +165,11 @@ func Test_parse(t *testing.T) {
|
|||
},
|
||||
{
|
||||
"//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
"//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
"http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87",
|
||||
},
|
||||
{
|
||||
"/gogs/avatars/2",
|
||||
"http://gogs.io/gogs/avatars/2",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/remote"
|
||||
"github.com/drone/drone/shared/token"
|
||||
"github.com/drone/drone/store"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
@ -43,9 +41,9 @@ func SetRepo() gin.HandlerFunc {
|
|||
var (
|
||||
owner = c.Param("owner")
|
||||
name = c.Param("name")
|
||||
user = User(c)
|
||||
)
|
||||
|
||||
user := User(c)
|
||||
repo, err := store.GetRepoOwnerName(c, owner, name)
|
||||
if err == nil {
|
||||
c.Set("repo", repo)
|
||||
|
@ -53,43 +51,18 @@ func SetRepo() gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
// if the user is not nil, check the remote system
|
||||
// to see if the repository actually exists. If yes,
|
||||
// we can prompt the user to add.
|
||||
// debugging
|
||||
log.Debugf("Cannot find repository %s/%s. %s",
|
||||
owner,
|
||||
name,
|
||||
err.Error(),
|
||||
)
|
||||
|
||||
if user != nil {
|
||||
remote := remote.FromContext(c)
|
||||
repo, err = remote.Repo(user, owner, name)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot find remote repository %s/%s for user %s. %s",
|
||||
owner, name, user.Login, err)
|
||||
} else {
|
||||
log.Debugf("Found remote repository %s/%s for user %s",
|
||||
owner, name, user.Login)
|
||||
}
|
||||
}
|
||||
|
||||
data := gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
}
|
||||
|
||||
// if we found a repository, we should display a page
|
||||
// to the user allowing them to activate.
|
||||
if repo != nil && len(repo.FullName) != 0 {
|
||||
// we should probably move this code to a
|
||||
// separate route, but for now we need to
|
||||
// add a CSRF token.
|
||||
data["Csrf"], _ = token.New(
|
||||
token.CsrfToken,
|
||||
user.Login,
|
||||
).Sign(user.Hash)
|
||||
|
||||
c.HTML(http.StatusNotFound, "repo_activate.html", data)
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
} else {
|
||||
c.HTML(http.StatusNotFound, "404.html", data)
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +148,6 @@ func SetPerm() gin.HandlerFunc {
|
|||
|
||||
func MustPull(c *gin.Context) {
|
||||
user := User(c)
|
||||
repo := Repo(c)
|
||||
perm := Perm(c)
|
||||
|
||||
if perm.Pull {
|
||||
|
@ -183,21 +155,22 @@ func MustPull(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// if the user doesn't have pull permission to the
|
||||
// repository we display a 404 error to avoid leaking
|
||||
// repository information.
|
||||
c.HTML(http.StatusNotFound, "404.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Perm": perm,
|
||||
})
|
||||
|
||||
c.Abort()
|
||||
// debugging
|
||||
if user != nil {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
log.Debugf("User %s denied read access to %s",
|
||||
user.Login, c.Request.URL.Path)
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
log.Debugf("Guest denied read access to %s %s",
|
||||
c.Request.Method,
|
||||
c.Request.URL.Path,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func MustPush(c *gin.Context) {
|
||||
user := User(c)
|
||||
repo := Repo(c)
|
||||
perm := Perm(c)
|
||||
|
||||
// if the user has push access, immediately proceed
|
||||
|
@ -207,32 +180,17 @@ func MustPush(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
data := gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Perm": perm,
|
||||
}
|
||||
|
||||
// if the user has pull access we should tell them
|
||||
// the operation is not authorized. Otherwise we should
|
||||
// give a 404 to avoid leaking information.
|
||||
if !perm.Pull {
|
||||
c.HTML(http.StatusNotFound, "404.html", data)
|
||||
} else {
|
||||
c.HTML(http.StatusUnauthorized, "401.html", data)
|
||||
}
|
||||
|
||||
// debugging
|
||||
if user != nil {
|
||||
log.Debugf("%s denied write access to %s",
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
log.Debugf("User %s denied write access to %s",
|
||||
user.Login, c.Request.URL.Path)
|
||||
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
log.Debugf("Guest denied write access to %s %s",
|
||||
c.Request.Method,
|
||||
c.Request.URL.Path,
|
||||
)
|
||||
}
|
||||
|
||||
c.Abort()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package router
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
|
@ -10,17 +9,23 @@ import (
|
|||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/router/middleware/token"
|
||||
"github.com/drone/drone/server"
|
||||
"github.com/drone/drone/static"
|
||||
"github.com/drone/drone/template"
|
||||
"github.com/drone/drone/server/template"
|
||||
|
||||
"github.com/drone/drone-ui/dist"
|
||||
)
|
||||
|
||||
// Load loads the router
|
||||
func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||
|
||||
e := gin.New()
|
||||
e.Use(gin.Recovery())
|
||||
|
||||
e.SetHTMLTemplate(template.Load())
|
||||
e.StaticFS("/static", static.FileSystem())
|
||||
|
||||
fs := http.FileServer(dist.AssetFS())
|
||||
e.GET("/static/*filepath", func(c *gin.Context) {
|
||||
fs.ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
|
||||
e.Use(header.NoCache)
|
||||
e.Use(header.Options)
|
||||
|
@ -29,35 +34,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
e.Use(session.SetUser())
|
||||
e.Use(token.Refresh)
|
||||
|
||||
e.GET("/", server.ShowIndex)
|
||||
e.GET("/repos", server.ShowAllRepos)
|
||||
e.GET("/login", server.ShowLogin)
|
||||
e.GET("/login/form", server.ShowLoginForm)
|
||||
e.GET("/logout", server.GetLogout)
|
||||
e.NoRoute(server.ShowIndex)
|
||||
|
||||
// TODO below will Go away with React UI
|
||||
settings := e.Group("/settings")
|
||||
{
|
||||
settings.Use(session.MustUser())
|
||||
settings.GET("/profile", server.ShowUser)
|
||||
}
|
||||
repo := e.Group("/repos/:owner/:name")
|
||||
{
|
||||
repo.Use(session.SetRepo())
|
||||
repo.Use(session.SetPerm())
|
||||
repo.Use(session.MustPull)
|
||||
|
||||
repo.GET("", server.ShowRepo)
|
||||
repo.GET("/builds/:number", server.ShowBuild)
|
||||
repo.GET("/builds/:number/:job", server.ShowBuild)
|
||||
|
||||
repo_settings := repo.Group("/settings")
|
||||
{
|
||||
repo_settings.GET("", session.MustPush, server.ShowRepoConf)
|
||||
repo_settings.GET("/encrypt", session.MustPush, server.ShowRepoEncrypt)
|
||||
repo_settings.GET("/badges", server.ShowRepoBadges)
|
||||
}
|
||||
}
|
||||
// TODO above will Go away with React UI
|
||||
|
||||
user := e.Group("/api/user")
|
||||
|
@ -97,6 +78,7 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
repo.GET("/logs/:number/:job", server.GetBuildLogs)
|
||||
repo.POST("/sign", session.MustPush, server.Sign)
|
||||
|
||||
repo.GET("/secrets", session.MustPush, server.GetSecrets)
|
||||
repo.POST("/secrets", session.MustPush, server.PostSecret)
|
||||
repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret)
|
||||
|
||||
|
@ -128,6 +110,16 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
stream.GET("/:owner/:name", server.GetRepoEvents)
|
||||
stream.GET("/:owner/:name/:build/:number", server.GetStream)
|
||||
}
|
||||
ws := e.Group("/ws")
|
||||
{
|
||||
ws.GET("/feed", server.EventStream)
|
||||
ws.GET("/logs/:owner/:name/:build/:number",
|
||||
session.SetRepo(),
|
||||
session.SetPerm(),
|
||||
session.MustPull,
|
||||
server.LogStream,
|
||||
)
|
||||
}
|
||||
|
||||
auth := e.Group("/authorize")
|
||||
{
|
||||
|
@ -183,34 +175,5 @@ func Load(middleware ...gin.HandlerFunc) http.Handler {
|
|||
// bots.POST("/slack/:command", Slack)
|
||||
// }
|
||||
|
||||
return normalize(e)
|
||||
}
|
||||
|
||||
// THIS HACK JOB IS GOING AWAY SOON.
|
||||
//
|
||||
// normalize is a helper function to work around the following
|
||||
// issue with gin. https://github.com/gin-gonic/gin/issues/388
|
||||
func normalize(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
parts := strings.Split(r.URL.Path, "/")[1:]
|
||||
switch parts[0] {
|
||||
case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
|
||||
// no-op
|
||||
default:
|
||||
|
||||
if len(parts) > 2 && parts[2] != "settings" {
|
||||
parts = append(parts[:2], append([]string{"builds"}, parts[2:]...)...)
|
||||
}
|
||||
|
||||
// prefix the URL with /repo so that it
|
||||
// can be effectively routed.
|
||||
parts = append([]string{"", "repos"}, parts...)
|
||||
|
||||
// reconstruct the path
|
||||
r.URL.Path = strings.Join(parts, "/")
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
return e
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
|
@ -42,7 +43,8 @@ func GetBadge(c *gin.Context) {
|
|||
|
||||
build, err := store.GetBuildLast(c, repo, branch)
|
||||
if err != nil {
|
||||
c.String(404, badgeNone)
|
||||
log.Warning(err)
|
||||
c.String(200, badgeNone)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -56,7 +58,7 @@ func GetBadge(c *gin.Context) {
|
|||
case model.StatusPending, model.StatusRunning:
|
||||
c.String(200, badgeStarted)
|
||||
default:
|
||||
c.String(404, badgeNone)
|
||||
c.String(200, badgeNone)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,11 +110,7 @@ func GetLogin(c *gin.Context) {
|
|||
}
|
||||
|
||||
httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr)
|
||||
redirect := httputil.GetCookie(c.Request, "user_last")
|
||||
if len(redirect) == 0 {
|
||||
redirect = "/"
|
||||
}
|
||||
c.Redirect(303, redirect)
|
||||
c.Redirect(303, "/")
|
||||
|
||||
}
|
||||
|
||||
|
|
201
server/pages.go
|
@ -1,192 +1,15 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/shared/httputil"
|
||||
"github.com/drone/drone/shared/token"
|
||||
"github.com/drone/drone/store"
|
||||
)
|
||||
|
||||
// ShowIndex serves the main Drone application page.
|
||||
func ShowIndex(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
if user == nil {
|
||||
c.Redirect(http.StatusSeeOther, "/login")
|
||||
return
|
||||
}
|
||||
|
||||
// get the repository list from the cache
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// filter to only show the currently active ones
|
||||
activeRepos, err := store.GetRepoListOf(c, repos)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.HTML(200, "index.html", gin.H{
|
||||
"User": user,
|
||||
"Repos": activeRepos,
|
||||
})
|
||||
}
|
||||
|
||||
func ShowAllRepos(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
if user == nil {
|
||||
c.Redirect(http.StatusSeeOther, "/login")
|
||||
return
|
||||
}
|
||||
|
||||
// get the repository list from the cache
|
||||
repos, err := cache.GetRepos(c, user)
|
||||
if err != nil {
|
||||
c.String(400, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.HTML(200, "repos.html", gin.H{
|
||||
"User": user,
|
||||
"Repos": repos,
|
||||
})
|
||||
}
|
||||
|
||||
func ShowLogin(c *gin.Context) {
|
||||
c.HTML(200, "login.html", gin.H{"Error": c.Query("error")})
|
||||
}
|
||||
|
||||
func ShowLoginForm(c *gin.Context) {
|
||||
c.HTML(200, "login_form.html", gin.H{})
|
||||
}
|
||||
|
||||
func ShowUser(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
token, _ := token.New(
|
||||
token.CsrfToken,
|
||||
user.Login,
|
||||
).Sign(user.Hash)
|
||||
|
||||
c.HTML(200, "user.html", gin.H{
|
||||
"User": user,
|
||||
"Csrf": token,
|
||||
})
|
||||
}
|
||||
|
||||
func ShowRepo(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
repo := session.Repo(c)
|
||||
|
||||
builds, _ := store.GetBuildList(c, repo)
|
||||
groups := []*model.BuildGroup{}
|
||||
|
||||
var curr *model.BuildGroup
|
||||
for _, build := range builds {
|
||||
date := time.Unix(build.Created, 0).Format("Jan 2 2006")
|
||||
if curr == nil || curr.Date != date {
|
||||
curr = &model.BuildGroup{}
|
||||
curr.Date = date
|
||||
groups = append(groups, curr)
|
||||
}
|
||||
curr.Builds = append(curr.Builds, build)
|
||||
}
|
||||
|
||||
httputil.SetCookie(c.Writer, c.Request, "user_last", repo.FullName)
|
||||
|
||||
c.HTML(200, "repo.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Builds": builds,
|
||||
"Groups": groups,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func ShowRepoConf(c *gin.Context) {
|
||||
|
||||
user := session.User(c)
|
||||
repo := session.Repo(c)
|
||||
|
||||
token, _ := token.New(
|
||||
token.CsrfToken,
|
||||
user.Login,
|
||||
).Sign(user.Hash)
|
||||
|
||||
c.HTML(200, "repo_config.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Csrf": token,
|
||||
"Link": httputil.GetURL(c.Request),
|
||||
})
|
||||
}
|
||||
|
||||
func ShowRepoEncrypt(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
repo := session.Repo(c)
|
||||
|
||||
token, _ := token.New(
|
||||
token.CsrfToken,
|
||||
user.Login,
|
||||
).Sign(user.Hash)
|
||||
|
||||
c.HTML(200, "repo_secret.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Csrf": token,
|
||||
})
|
||||
}
|
||||
|
||||
func ShowRepoBadges(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
repo := session.Repo(c)
|
||||
|
||||
c.HTML(200, "repo_badge.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Link": httputil.GetURL(c.Request),
|
||||
})
|
||||
}
|
||||
|
||||
func ShowBuild(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
repo := session.Repo(c)
|
||||
num, _ := strconv.Atoi(c.Param("number"))
|
||||
seq, _ := strconv.Atoi(c.Param("job"))
|
||||
if seq == 0 {
|
||||
seq = 1
|
||||
}
|
||||
|
||||
build, err := store.GetBuildNumber(c, repo, num)
|
||||
if err != nil {
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
jobs, err := store.GetJobList(c, build)
|
||||
if err != nil {
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
var job *model.Job
|
||||
for _, j := range jobs {
|
||||
if j.Number == seq {
|
||||
job = j
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
httputil.SetCookie(c.Writer, c.Request, "user_last", repo.FullName)
|
||||
|
||||
var csrf string
|
||||
if user != nil {
|
||||
|
@ -196,12 +19,20 @@ func ShowBuild(c *gin.Context) {
|
|||
).Sign(user.Hash)
|
||||
}
|
||||
|
||||
c.HTML(200, "build.html", gin.H{
|
||||
"User": user,
|
||||
"Repo": repo,
|
||||
"Build": build,
|
||||
"Jobs": jobs,
|
||||
"Job": job,
|
||||
"Csrf": csrf,
|
||||
c.HTML(200, "index.html", gin.H{
|
||||
"user": user,
|
||||
"csrf": csrf,
|
||||
})
|
||||
}
|
||||
|
||||
// ShowLogin is a legacy endpoint that now redirects to
|
||||
// initiliaze the oauth flow
|
||||
func ShowLogin(c *gin.Context) {
|
||||
c.Redirect(303, "/authorize")
|
||||
}
|
||||
|
||||
// ShowLoginForm displays a login form for systems like Gogs that do not
|
||||
// yet support oauth workflows.
|
||||
func ShowLoginForm(c *gin.Context) {
|
||||
c.HTML(200, "login.html", gin.H{})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/store"
|
||||
|
@ -8,13 +10,31 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetSecrets(c *gin.Context) {
|
||||
repo := session.Repo(c)
|
||||
secrets, err := store.GetSecretList(c, repo)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var list []*model.Secret
|
||||
|
||||
for _, s := range secrets {
|
||||
list = append(list, s.Clone())
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, list)
|
||||
}
|
||||
|
||||
func PostSecret(c *gin.Context) {
|
||||
repo := session.Repo(c)
|
||||
|
||||
in := &model.Secret{}
|
||||
err := c.Bind(in)
|
||||
if err != nil {
|
||||
c.String(400, "Invalid JSON input. %s", err.Error())
|
||||
c.String(http.StatusBadRequest, "Invalid JSON input. %s", err.Error())
|
||||
return
|
||||
}
|
||||
in.ID = 0
|
||||
|
@ -22,11 +42,11 @@ func PostSecret(c *gin.Context) {
|
|||
|
||||
err = store.SetSecret(c, in)
|
||||
if err != nil {
|
||||
c.String(500, "Unable to persist secret. %s", err.Error())
|
||||
c.String(http.StatusInternalServerError, "Unable to persist secret. %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.String(200, "")
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
||||
func DeleteSecret(c *gin.Context) {
|
||||
|
@ -35,14 +55,14 @@ func DeleteSecret(c *gin.Context) {
|
|||
|
||||
secret, err := store.GetSecret(c, repo, name)
|
||||
if err != nil {
|
||||
c.String(404, "Cannot find secret %s.", name)
|
||||
c.String(http.StatusNotFound, "Cannot find secret %s.", name)
|
||||
return
|
||||
}
|
||||
err = store.DeleteSecret(c, secret)
|
||||
if err != nil {
|
||||
c.String(500, "Unable to delete secret. %s", err.Error())
|
||||
c.String(http.StatusInternalServerError, "Unable to delete secret. %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.String(200, "")
|
||||
c.String(http.StatusOK, "")
|
||||
}
|
||||
|
|
188
server/stream.go
|
@ -5,17 +5,18 @@ import (
|
|||
"encoding/json"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/bus"
|
||||
"github.com/drone/drone/cache"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/drone/drone/router/middleware/session"
|
||||
"github.com/drone/drone/store"
|
||||
"github.com/drone/drone/stream"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/manucorporat/sse"
|
||||
)
|
||||
|
||||
|
@ -30,14 +31,14 @@ func GetRepoEvents(c *gin.Context) {
|
|||
defer func() {
|
||||
bus.Unsubscribe(c, eventc)
|
||||
close(eventc)
|
||||
log.Infof("closed event stream")
|
||||
logrus.Infof("closed event stream")
|
||||
}()
|
||||
|
||||
c.Stream(func(w io.Writer) bool {
|
||||
select {
|
||||
case event := <-eventc:
|
||||
if event == nil {
|
||||
log.Infof("nil event received")
|
||||
logrus.Infof("nil event received")
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -75,13 +76,13 @@ func GetStream(c *gin.Context) {
|
|||
|
||||
build, err := store.GetBuildNumber(c, repo, buildn)
|
||||
if err != nil {
|
||||
log.Debugln("stream cannot get build number.", err)
|
||||
logrus.Debugln("stream cannot get build number.", err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
job, err := store.GetJobNumber(c, build, jobn)
|
||||
if err != nil {
|
||||
log.Debugln("stream cannot get job number.", err)
|
||||
logrus.Debugln("stream cannot get job number.", err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
@ -112,5 +113,174 @@ func GetStream(c *gin.Context) {
|
|||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
log.Debugf("Closed stream %s#%d", repo.FullName, build.Number)
|
||||
logrus.Debugf("Closed stream %s#%d", repo.FullName, build.Number)
|
||||
}
|
||||
|
||||
var (
|
||||
// Time allowed to write the file to the client.
|
||||
writeWait = 5 * time.Second
|
||||
|
||||
// Time allowed to read the next pong message from the client.
|
||||
pongWait = 60 * time.Second
|
||||
|
||||
// Send pings to client with this period. Must be less than pongWait.
|
||||
pingPeriod = 30 * time.Second
|
||||
)
|
||||
|
||||
// LogStream streams the build log output to the client.
|
||||
func LogStream(c *gin.Context) {
|
||||
repo := session.Repo(c)
|
||||
buildn, _ := strconv.Atoi(c.Param("build"))
|
||||
jobn, _ := strconv.Atoi(c.Param("number"))
|
||||
|
||||
c.Writer.Header().Set("Content-Type", "text/event-stream")
|
||||
|
||||
build, err := store.GetBuildNumber(c, repo, buildn)
|
||||
if err != nil {
|
||||
logrus.Debugln("stream cannot get build number.", err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
job, err := store.GetJobNumber(c, build, jobn)
|
||||
if err != nil {
|
||||
logrus.Debugln("stream cannot get job number.", err)
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
if job.Status != model.StatusRunning {
|
||||
logrus.Debugln("stream not found.")
|
||||
c.AbortWithStatus(404)
|
||||
return
|
||||
}
|
||||
|
||||
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(websocket.HandshakeError); !ok {
|
||||
logrus.Errorf("Cannot upgrade websocket. %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
logrus.Debugf("Successfull upgraded websocket")
|
||||
|
||||
ticker := time.NewTicker(pingPeriod)
|
||||
defer ticker.Stop()
|
||||
|
||||
rc, err := stream.Reader(c, stream.ToKey(job.ID))
|
||||
if err != nil {
|
||||
c.AbortWithError(404, err)
|
||||
return
|
||||
}
|
||||
|
||||
quitc := make(chan bool)
|
||||
defer func() {
|
||||
quitc <- true
|
||||
close(quitc)
|
||||
rc.Close()
|
||||
ws.Close()
|
||||
logrus.Debug("Successfully closed websocket")
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-quitc:
|
||||
return
|
||||
case <-ticker.C:
|
||||
err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var scanner = bufio.NewScanner(rc)
|
||||
var b []byte
|
||||
for scanner.Scan() {
|
||||
b = scanner.Bytes()
|
||||
if len(b) == 0 {
|
||||
continue
|
||||
}
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
ws.WriteMessage(websocket.TextMessage, b)
|
||||
}
|
||||
}
|
||||
|
||||
// EventStream produces the User event stream, sending all repository, build
|
||||
// and agent events to the client.
|
||||
func EventStream(c *gin.Context) {
|
||||
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(websocket.HandshakeError); !ok {
|
||||
logrus.Errorf("Cannot upgrade websocket. %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
logrus.Debugf("Successfull upgraded websocket")
|
||||
|
||||
user := session.User(c)
|
||||
repo := map[string]bool{}
|
||||
if user != nil {
|
||||
repo, _ = cache.GetRepoMap(c, user)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(pingPeriod)
|
||||
quitc := make(chan bool)
|
||||
eventc := make(chan *bus.Event, 10)
|
||||
bus.Subscribe(c, eventc)
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
bus.Unsubscribe(c, eventc)
|
||||
quitc <- true
|
||||
close(quitc)
|
||||
close(eventc)
|
||||
ws.Close()
|
||||
logrus.Debug("Successfully closed websocket")
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-quitc:
|
||||
return
|
||||
case event := <-eventc:
|
||||
if event == nil {
|
||||
return
|
||||
}
|
||||
if repo[event.Repo.FullName] || !event.Repo.IsPrivate {
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
ws.WriteJSON(event)
|
||||
}
|
||||
case <-ticker.C:
|
||||
err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
reader(ws)
|
||||
}
|
||||
|
||||
func reader(ws *websocket.Conn) {
|
||||
defer ws.Close()
|
||||
ws.SetReadLimit(512)
|
||||
ws.SetReadDeadline(time.Now().Add(pongWait))
|
||||
ws.SetPongHandler(func(string) error {
|
||||
ws.SetReadDeadline(time.Now().Add(pongWait))
|
||||
return nil
|
||||
})
|
||||
for {
|
||||
_, _, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
22
server/template/files/index.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<meta content="ie=edge" http-equiv="x-ua-compatible"/>
|
||||
{{ if .csrf }}<meta name="csrf-token" content="{{ .csrf }}" />{{ end }}
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
|
||||
<link href="/static/app.css" rel="stylesheet"/>
|
||||
<link href="/static/favicon.ico" rel="icon" type="image/x-icon"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.STATE_FROM_SERVER={{ . | json }};
|
||||
</script>
|
||||
<script src="https://code.getmdl.io/1.1.3/material.min.js"></script>
|
||||
<script src="/static/app.js"></script>
|
||||
</body>
|
||||
</html>
|
20
server/template/files/login.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<meta content="ie=edge" http-equiv="x-ua-compatible"/>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
|
||||
<link href="/static/favicon.ico" rel="icon" type="image/x-icon"/>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/authorize" method="post">
|
||||
<input type="text" placeholder="Username" name="username" />
|
||||
<input type="password" placeholder="Password" name="password" />
|
||||
<input type="submit" value="Login" />
|
||||
</form>
|
||||
<script src="https://code.getmdl.io/1.1.3/material.min.js"></script>
|
||||
</body>
|
||||
</html>
|
1
server/template/files/logout.html
Normal file
|
@ -0,0 +1 @@
|
|||
LOGOUT
|
31
server/template/template.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
package template
|
||||
|
||||
//go:generate go-bindata -pkg template -o template_gen.go files/
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Load loads the templates from the embedded file map. This function will not
|
||||
// compile if go generate is not executed before.
|
||||
func Load() *template.Template {
|
||||
dir, _ := AssetDir("files")
|
||||
tmpl := template.New("_").Funcs(template.FuncMap{"json": marshal})
|
||||
for _, name := range dir {
|
||||
path := filepath.Join("files", name)
|
||||
src := MustAsset(path)
|
||||
tmpl = template.Must(
|
||||
tmpl.New(name).Parse(string(src)),
|
||||
)
|
||||
}
|
||||
|
||||
return tmpl
|
||||
}
|
||||
|
||||
// marshal is a helper function to render data as JSON inside the template.
|
||||
func marshal(v interface{}) template.JS {
|
||||
a, _ := json.Marshal(v)
|
||||
return template.JS(a)
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="466px" height="423.891px" viewBox="0 0 466 423.891" enable-background="new 0 0 466 423.891" xml:space="preserve">
|
||||
<rect x="-43.5" y="37.005" display="none" fill-rule="evenodd" clip-rule="evenodd" fill="#E7E7E7" width="792" height="612"/>
|
||||
<g>
|
||||
<path id="outline_7_" fill-rule="evenodd" clip-rule="evenodd" d="M242.133,168.481h47.146v48.194h23.837
|
||||
c11.008,0,22.33-1.962,32.755-5.494c5.123-1.736,10.872-4.154,15.926-7.193c-6.656-8.689-10.053-19.661-11.054-30.476
|
||||
c-1.358-14.71,1.609-33.855,11.564-45.368l4.956-5.732l5.905,4.747c14.867,11.946,27.372,28.638,29.577,47.665
|
||||
c17.901-5.266,38.921-4.02,54.701,5.088l6.475,3.734l-3.408,6.652c-13.345,26.046-41.246,34.113-68.524,32.687
|
||||
c-40.817,101.663-129.68,149.794-237.428,149.794c-55.666,0-106.738-20.81-135.821-70.197l-0.477-0.807l-4.238-8.621
|
||||
C4.195,271.415,0.93,247.6,3.145,223.803l0.664-7.127h40.315v-48.194h47.143v-47.145h94.292V74.191h56.574V168.481z"/>
|
||||
<g display="none">
|
||||
<path display="inline" fill="#394D54" d="M61.093,319.89c6.023,0,11.763-0.157,17.219-0.464c0.476-0.026,0.932-0.063,1.402-0.092
|
||||
c0.005-0.002,0.008-0.002,0.012-0.002c13.872-0.855,25.876-2.708,35.902-5.57c0.002-0.002,0.004-0.002,0.006-0.002
|
||||
c1.823-0.521,3.588-1.07,5.282-1.656c1.894-0.657,2.896-2.725,2.241-4.618c-0.656-1.895-2.722-2.899-4.618-2.24
|
||||
c-12.734,4.412-29.535,6.842-50.125,7.298c-0.002,0-0.004,0-0.005,0c-10.477,0.232-21.93-0.044-34.352-0.843c0,0,0,0-0.001,0
|
||||
c-0.635-0.038-1.259-0.075-1.9-0.118c-1.995-0.128-3.731,1.374-3.869,3.375c-0.136,1.999,1.376,3.73,3.375,3.866
|
||||
c2.537,0.173,5.03,0.321,7.49,0.453c0.392,0.021,0.77,0.034,1.158,0.054l0,0C47.566,319.697,54.504,319.89,61.093,319.89z"/>
|
||||
</g>
|
||||
<g id="Containers_8_">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M86.209,179.744h3.227v34.052h-3.227V179.744z M80.02,179.744
|
||||
h3.354v34.052H80.02V179.744z M73.828,179.744h3.354v34.052h-3.354V179.744z M67.636,179.744h3.354v34.052h-3.354V179.744z
|
||||
M61.446,179.744H64.8v34.052h-3.354V179.744z M55.384,179.744h3.224v34.052h-3.224V179.744z M51.981,176.338h40.858v40.86H51.981
|
||||
V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,132.598h3.229v34.051h-3.229V132.598z M127.165,132.598
|
||||
h3.354v34.051h-3.354V132.598z M120.973,132.598h3.354v34.051h-3.354V132.598z M114.781,132.598h3.354v34.051h-3.354V132.598z
|
||||
M108.593,132.598h3.352v34.051h-3.352V132.598z M102.531,132.598h3.222v34.051h-3.222V132.598z M99.124,129.193h40.863v40.859
|
||||
H99.124V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,179.744h3.229v34.052h-3.229V179.744z M127.165,179.744
|
||||
h3.354v34.052h-3.354V179.744z M120.973,179.744h3.354v34.052h-3.354V179.744z M114.781,179.744h3.354v34.052h-3.354V179.744z
|
||||
M108.593,179.744h3.352v34.052h-3.352V179.744z M102.531,179.744h3.222v34.052h-3.222V179.744z M99.124,176.338h40.863v40.86
|
||||
H99.124V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,179.744h3.225v34.052h-3.225V179.744z M174.31,179.744
|
||||
h3.355v34.052h-3.355V179.744z M168.12,179.744h3.354v34.052h-3.354V179.744z M161.928,179.744h3.354v34.052h-3.354V179.744z
|
||||
M155.736,179.744h3.354v34.052h-3.354V179.744z M149.676,179.744h3.222v34.052h-3.222V179.744z M146.271,176.338h40.861v40.86
|
||||
h-40.861V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,132.598h3.225v34.051h-3.225V132.598z M174.31,132.598
|
||||
h3.355v34.051h-3.355V132.598z M168.12,132.598h3.354v34.051h-3.354V132.598z M161.928,132.598h3.354v34.051h-3.354V132.598z
|
||||
M155.736,132.598h3.354v34.051h-3.354V132.598z M149.676,132.598h3.222v34.051h-3.222V132.598z M146.271,129.193h40.861v40.859
|
||||
h-40.861V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,179.744h3.226v34.052h-3.226V179.744z M221.457,179.744
|
||||
h3.354v34.052h-3.354V179.744z M215.265,179.744h3.354v34.052h-3.354V179.744z M209.073,179.744h3.354v34.052h-3.354V179.744z
|
||||
M202.884,179.744h3.354v34.052h-3.354V179.744z M196.821,179.744h3.224v34.052h-3.224V179.744z M193.416,176.338h40.861v40.86
|
||||
h-40.861V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,132.598h3.226v34.051h-3.226V132.598z M221.457,132.598
|
||||
h3.354v34.051h-3.354V132.598z M215.265,132.598h3.354v34.051h-3.354V132.598z M209.073,132.598h3.354v34.051h-3.354V132.598z
|
||||
M202.884,132.598h3.354v34.051h-3.354V132.598z M196.821,132.598h3.224v34.051h-3.224V132.598z M193.416,129.193h40.861v40.859
|
||||
h-40.861V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,85.451h3.226v34.053h-3.226V85.451z M221.457,85.451
|
||||
h3.354v34.053h-3.354V85.451z M215.265,85.451h3.354v34.053h-3.354V85.451z M209.073,85.451h3.354v34.053h-3.354V85.451z
|
||||
M202.884,85.451h3.354v34.053h-3.354V85.451z M196.821,85.451h3.224v34.053h-3.224V85.451z M193.416,82.048h40.861v40.86h-40.861
|
||||
V82.048z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M274.792,179.744h3.224v34.052h-3.224V179.744z M268.602,179.744
|
||||
h3.352v34.052h-3.352V179.744z M262.408,179.744h3.354v34.052h-3.354V179.744z M256.218,179.744h3.354v34.052h-3.354V179.744z
|
||||
M250.026,179.744h3.354v34.052h-3.354V179.744z M243.964,179.744h3.227v34.052h-3.227V179.744z M240.561,176.338h40.86v40.86
|
||||
h-40.86V176.338z"/>
|
||||
</g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M137.428,283.445c6.225,0,11.271,5.049,11.271,11.272
|
||||
c0,6.225-5.046,11.271-11.271,11.271c-6.226,0-11.272-5.046-11.272-11.271C126.156,288.494,131.202,283.445,137.428,283.445"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M137.428,286.644c1.031,0,2.015,0.194,2.923,0.546
|
||||
c-0.984,0.569-1.65,1.635-1.65,2.854c0,1.82,1.476,3.293,3.296,3.293c1.247,0,2.329-0.693,2.89-1.715
|
||||
c0.395,0.953,0.615,1.999,0.615,3.097c0,4.458-3.615,8.073-8.073,8.073c-4.458,0-8.074-3.615-8.074-8.073
|
||||
C129.354,290.258,132.971,286.644,137.428,286.644"/>
|
||||
<path fill="#FFFFFF" d="M167.394,364.677c-27.916-13.247-43.239-31.256-51.765-50.915c-10.37,2.961-22.835,4.852-37.317,5.664
|
||||
c-5.457,0.307-11.196,0.464-17.219,0.464c-6.942,0-14.26-0.205-21.94-0.613c25.6,25.585,57.094,45.283,115.408,45.645
|
||||
C158.866,364.921,163.14,364.837,167.394,364.677z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 6.4 KiB |
|
@ -1,70 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="466px" height="423.891px" viewBox="0 0 466 423.891" enable-background="new 0 0 466 423.891" xml:space="preserve">
|
||||
<rect x="-43.5" y="37.005" display="none" fill-rule="evenodd" clip-rule="evenodd" fill="#E7E7E7" width="792" height="612"/>
|
||||
<g>
|
||||
<path fill="#6699cc" id="outline_7_" fill-rule="evenodd" clip-rule="evenodd" d="M242.133,168.481h47.146v48.194h23.837
|
||||
c11.008,0,22.33-1.962,32.755-5.494c5.123-1.736,10.872-4.154,15.926-7.193c-6.656-8.689-10.053-19.661-11.054-30.476
|
||||
c-1.358-14.71,1.609-33.855,11.564-45.368l4.956-5.732l5.905,4.747c14.867,11.946,27.372,28.638,29.577,47.665
|
||||
c17.901-5.266,38.921-4.02,54.701,5.088l6.475,3.734l-3.408,6.652c-13.345,26.046-41.246,34.113-68.524,32.687
|
||||
c-40.817,101.663-129.68,149.794-237.428,149.794c-55.666,0-106.738-20.81-135.821-70.197l-0.477-0.807l-4.238-8.621
|
||||
C4.195,271.415,0.93,247.6,3.145,223.803l0.664-7.127h40.315v-48.194h47.143v-47.145h94.292V74.191h56.574V168.481z"/>
|
||||
<g display="none">
|
||||
<path display="inline" fill="#394D54" d="M61.093,319.89c6.023,0,11.763-0.157,17.219-0.464c0.476-0.026,0.932-0.063,1.402-0.092
|
||||
c0.005-0.002,0.008-0.002,0.012-0.002c13.872-0.855,25.876-2.708,35.902-5.57c0.002-0.002,0.004-0.002,0.006-0.002
|
||||
c1.823-0.521,3.588-1.07,5.282-1.656c1.894-0.657,2.896-2.725,2.241-4.618c-0.656-1.895-2.722-2.899-4.618-2.24
|
||||
c-12.734,4.412-29.535,6.842-50.125,7.298c-0.002,0-0.004,0-0.005,0c-10.477,0.232-21.93-0.044-34.352-0.843c0,0,0,0-0.001,0
|
||||
c-0.635-0.038-1.259-0.075-1.9-0.118c-1.995-0.128-3.731,1.374-3.869,3.375c-0.136,1.999,1.376,3.73,3.375,3.866
|
||||
c2.537,0.173,5.03,0.321,7.49,0.453c0.392,0.021,0.77,0.034,1.158,0.054l0,0C47.566,319.697,54.504,319.89,61.093,319.89z"/>
|
||||
</g>
|
||||
<g id="Containers_8_">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M86.209,179.744h3.227v34.052h-3.227V179.744z M80.02,179.744
|
||||
h3.354v34.052H80.02V179.744z M73.828,179.744h3.354v34.052h-3.354V179.744z M67.636,179.744h3.354v34.052h-3.354V179.744z
|
||||
M61.446,179.744H64.8v34.052h-3.354V179.744z M55.384,179.744h3.224v34.052h-3.224V179.744z M51.981,176.338h40.858v40.86H51.981
|
||||
V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,132.598h3.229v34.051h-3.229V132.598z M127.165,132.598
|
||||
h3.354v34.051h-3.354V132.598z M120.973,132.598h3.354v34.051h-3.354V132.598z M114.781,132.598h3.354v34.051h-3.354V132.598z
|
||||
M108.593,132.598h3.352v34.051h-3.352V132.598z M102.531,132.598h3.222v34.051h-3.222V132.598z M99.124,129.193h40.863v40.859
|
||||
H99.124V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M133.354,179.744h3.229v34.052h-3.229V179.744z M127.165,179.744
|
||||
h3.354v34.052h-3.354V179.744z M120.973,179.744h3.354v34.052h-3.354V179.744z M114.781,179.744h3.354v34.052h-3.354V179.744z
|
||||
M108.593,179.744h3.352v34.052h-3.352V179.744z M102.531,179.744h3.222v34.052h-3.222V179.744z M99.124,176.338h40.863v40.86
|
||||
H99.124V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,179.744h3.225v34.052h-3.225V179.744z M174.31,179.744
|
||||
h3.355v34.052h-3.355V179.744z M168.12,179.744h3.354v34.052h-3.354V179.744z M161.928,179.744h3.354v34.052h-3.354V179.744z
|
||||
M155.736,179.744h3.354v34.052h-3.354V179.744z M149.676,179.744h3.222v34.052h-3.222V179.744z M146.271,176.338h40.861v40.86
|
||||
h-40.861V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M180.501,132.598h3.225v34.051h-3.225V132.598z M174.31,132.598
|
||||
h3.355v34.051h-3.355V132.598z M168.12,132.598h3.354v34.051h-3.354V132.598z M161.928,132.598h3.354v34.051h-3.354V132.598z
|
||||
M155.736,132.598h3.354v34.051h-3.354V132.598z M149.676,132.598h3.222v34.051h-3.222V132.598z M146.271,129.193h40.861v40.859
|
||||
h-40.861V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,179.744h3.226v34.052h-3.226V179.744z M221.457,179.744
|
||||
h3.354v34.052h-3.354V179.744z M215.265,179.744h3.354v34.052h-3.354V179.744z M209.073,179.744h3.354v34.052h-3.354V179.744z
|
||||
M202.884,179.744h3.354v34.052h-3.354V179.744z M196.821,179.744h3.224v34.052h-3.224V179.744z M193.416,176.338h40.861v40.86
|
||||
h-40.861V176.338z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,132.598h3.226v34.051h-3.226V132.598z M221.457,132.598
|
||||
h3.354v34.051h-3.354V132.598z M215.265,132.598h3.354v34.051h-3.354V132.598z M209.073,132.598h3.354v34.051h-3.354V132.598z
|
||||
M202.884,132.598h3.354v34.051h-3.354V132.598z M196.821,132.598h3.224v34.051h-3.224V132.598z M193.416,129.193h40.861v40.859
|
||||
h-40.861V129.193z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M227.647,85.451h3.226v34.053h-3.226V85.451z M221.457,85.451
|
||||
h3.354v34.053h-3.354V85.451z M215.265,85.451h3.354v34.053h-3.354V85.451z M209.073,85.451h3.354v34.053h-3.354V85.451z
|
||||
M202.884,85.451h3.354v34.053h-3.354V85.451z M196.821,85.451h3.224v34.053h-3.224V85.451z M193.416,82.048h40.861v40.86h-40.861
|
||||
V82.048z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M274.792,179.744h3.224v34.052h-3.224V179.744z M268.602,179.744
|
||||
h3.352v34.052h-3.352V179.744z M262.408,179.744h3.354v34.052h-3.354V179.744z M256.218,179.744h3.354v34.052h-3.354V179.744z
|
||||
M250.026,179.744h3.354v34.052h-3.354V179.744z M243.964,179.744h3.227v34.052h-3.227V179.744z M240.561,176.338h40.86v40.86
|
||||
h-40.86V176.338z"/>
|
||||
</g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M137.428,283.445c6.225,0,11.271,5.049,11.271,11.272
|
||||
c0,6.225-5.046,11.271-11.271,11.271c-6.226,0-11.272-5.046-11.272-11.271C126.156,288.494,131.202,283.445,137.428,283.445"/>
|
||||
<path fill="#6699cc" fill-rule="evenodd" clip-rule="evenodd" d="M137.428,286.644c1.031,0,2.015,0.194,2.923,0.546
|
||||
c-0.984,0.569-1.65,1.635-1.65,2.854c0,1.82,1.476,3.293,3.296,3.293c1.247,0,2.329-0.693,2.89-1.715
|
||||
c0.395,0.953,0.615,1.999,0.615,3.097c0,4.458-3.615,8.073-8.073,8.073c-4.458,0-8.074-3.615-8.074-8.073
|
||||
C129.354,290.258,132.971,286.644,137.428,286.644"/>
|
||||
<path fill="#FFFFFF" d="M167.394,364.677c-27.916-13.247-43.239-31.256-51.765-50.915c-10.37,2.961-22.835,4.852-37.317,5.664
|
||||
c-5.457,0.307-11.196,0.464-17.219,0.464c-6.942,0-14.26-0.205-21.94-0.613c25.6,25.585,57.094,45.283,115.408,45.645
|
||||
C158.866,364.921,163.14,364.837,167.394,364.677z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 6.4 KiB |
|
@ -1,13 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="466px" height="423.891px" viewBox="0 0 466 423.891" enable-background="new 0 0 466 423.891" xml:space="preserve">
|
||||
<rect x="-43.5" y="37.005" display="none" fill-rule="evenodd" clip-rule="evenodd" fill="#E7E7E7" width="792" height="612"/>
|
||||
<g>
|
||||
<path fill="#FFF" id="outline_7_" fill-rule="evenodd" clip-rule="evenodd" d="M242.133,168.481h47.146v48.194h23.837 c11.008,0,22.33-1.962,32.755-5.494c5.123-1.736,10.872-4.154,15.926-7.193c-6.656-8.689-10.053-19.661-11.054-30.476 c-1.358-14.71,1.609-33.855,11.564-45.368l4.956-5.732l5.905,4.747c14.867,11.946,27.372,28.638,29.577,47.665 c17.901-5.266,38.921-4.02,54.701,5.088l6.475,3.734l-3.408,6.652c-13.345,26.046-41.246,34.113-68.524,32.687 c-40.817,101.663-129.68,149.794-237.428,149.794c-55.666,0-106.738-20.81-135.821-70.197l-0.477-0.807l-4.238-8.621 C4.195,271.415,0.93,247.6,3.145,223.803l0.664-7.127h40.315v-48.194h47.143v-47.145h94.292V74.191h56.574V168.481z"/>
|
||||
<g display="none">
|
||||
<path display="inline" fill="#FFF" d="M61.093,319.89c6.023,0,11.763-0.157,17.219-0.464c0.476-0.026,0.932-0.063,1.402-0.092 c0.005-0.002,0.008-0.002,0.012-0.002c13.872-0.855,25.876-2.708,35.902-5.57c0.002-0.002,0.004-0.002,0.006-0.002 c1.823-0.521,3.588-1.07,5.282-1.656c1.894-0.657,2.896-2.725,2.241-4.618c-0.656-1.895-2.722-2.899-4.618-2.24 c-12.734,4.412-29.535,6.842-50.125,7.298c-0.002,0-0.004,0-0.005,0c-10.477,0.232-21.93-0.044-34.352-0.843c0,0,0,0-0.001,0 c-0.635-0.038-1.259-0.075-1.9-0.118c-1.995-0.128-3.731,1.374-3.869,3.375c-0.136,1.999,1.376,3.73,3.375,3.866 c2.537,0.173,5.03,0.321,7.49,0.453c0.392,0.021,0.77,0.034,1.158,0.054l0,0C47.566,319.697,54.504,319.89,61.093,319.89z"/>
|
||||
</g>
|
||||
|
||||
|
||||
|
||||
<path fill="#FFF" d="M167.394,364.677c-27.916-13.247-43.239-31.256-51.765-50.915c-10.37,2.961-22.835,4.852-37.317,5.664 c-5.457,0.307-11.196,0.464-17.219,0.464c-6.942,0-14.26-0.205-21.94-0.613c25.6,25.585,57.094,45.283,115.408,45.645 C158.866,364.921,163.14,364.837,167.394,364.677z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 366 B |
|
@ -1,93 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="43"
|
||||
height="36.350704"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="drone-logo-no-circle.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#2b303b"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="26.576205"
|
||||
inkscape:cy="-72.54425"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:window-width="1295"
|
||||
inkscape:window-height="744"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2996"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
originx="-21.720779px"
|
||||
originy="-990.37188px" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-21.720779,-25.639593)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#2b303b;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path2998"
|
||||
sodipodi:cx="172.10474"
|
||||
sodipodi:cy="458.39249"
|
||||
sodipodi:rx="5.4295697"
|
||||
sodipodi:ry="5.0507627"
|
||||
d="m 177.53431,458.39249 c 0,2.78946 -2.43091,5.05076 -5.42957,5.05076 -2.99867,0 -5.42957,-2.2613 -5.42957,-5.05076 0,-2.78946 2.4309,-5.05077 5.42957,-5.05077 2.99866,0 5.42957,2.26131 5.42957,5.05077 z"
|
||||
transform="matrix(1.0129716,0,0,1.0889445,-131.11643,-452.42373)" />
|
||||
<path
|
||||
style="fill:#2b303b;fill-opacity:1;stroke-width:0;stroke-miterlimit:4"
|
||||
d="m 43.220779,25.640247 c 9.60163,0.0752 20.51786,6.8438 21.5,19.6 l -13,0 c 0,0 -1.67472,-7.04733 -8.5,-7 -6.82528,0.0473 -8.5,7 -8.5,7 l -13,0 c 0.63161,-12.53073 11.36576,-19.67935 21.5,-19.6 z"
|
||||
id="rect3810"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scczccs" />
|
||||
<path
|
||||
style="fill:#2b303b;fill-opacity:1;stroke-width:0;stroke-miterlimit:4"
|
||||
d="m 43.310069,61.990247 c -7.159395,0.01905 -13.847588,-5.383347 -16.58929,-13.75 l 8,0 c 0,0 1.72575,6.96782 8.55103,6.92049 6.82528,-0.0473 8.44897,-6.92049 8.44897,-6.92049 l 8,0 c -1.783351,8.850973 -9.251314,13.730946 -16.41071,13.75 z"
|
||||
id="rect3810-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scczccs" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.4 KiB |
|
@ -1,93 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="43"
|
||||
height="36.350704"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="drone-logo-no-circle.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="26.576205"
|
||||
inkscape:cy="-72.54425"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:window-width="1295"
|
||||
inkscape:window-height="744"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2996"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true"
|
||||
originx="-21.720779px"
|
||||
originy="-990.37188px" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-21.720779,-25.639593)">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path2998"
|
||||
sodipodi:cx="172.10474"
|
||||
sodipodi:cy="458.39249"
|
||||
sodipodi:rx="5.4295697"
|
||||
sodipodi:ry="5.0507627"
|
||||
d="m 177.53431,458.39249 c 0,2.78946 -2.43091,5.05076 -5.42957,5.05076 -2.99867,0 -5.42957,-2.2613 -5.42957,-5.05076 0,-2.78946 2.4309,-5.05077 5.42957,-5.05077 2.99866,0 5.42957,2.26131 5.42957,5.05077 z"
|
||||
transform="matrix(1.0129716,0,0,1.0889445,-131.11643,-452.42373)" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0;stroke-miterlimit:4"
|
||||
d="m 43.220779,25.640247 c 9.60163,0.0752 20.51786,6.8438 21.5,19.6 l -13,0 c 0,0 -1.67472,-7.04733 -8.5,-7 -6.82528,0.0473 -8.5,7 -8.5,7 l -13,0 c 0.63161,-12.53073 11.36576,-19.67935 21.5,-19.6 z"
|
||||
id="rect3810"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scczccs" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0;stroke-miterlimit:4"
|
||||
d="m 43.310069,61.990247 c -7.159395,0.01905 -13.847588,-5.383347 -16.58929,-13.75 l 8,0 c 0,0 1.72575,6.96782 8.55103,6.92049 6.82528,-0.0473 8.44897,-6.92049 8.44897,-6.92049 l 8,0 c -1.783351,8.850973 -9.251314,13.730946 -16.41071,13.75 z"
|
||||
id="rect3810-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scczccs" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.4 KiB |
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="256px" height="256px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M255.637396,127.683191 C255.637396,198.196551 198.47207,255.363378 127.954205,255.363378 C57.4348387,255.363378 0.27026393,198.196551 0.27026393,127.683191 C0.27026393,57.1653255 57.4355894,0 127.954205,0 C198.472821,0 255.637396,57.1653255 255.637396,127.683191 L255.637396,127.683191 Z" fill="#DD4814"></path>
|
||||
<path d="M41.1334194,110.63254 C31.7139707,110.63254 24.0827683,118.264493 24.0827683,127.683191 C24.0827683,137.097384 31.7139707,144.728587 41.1334194,144.728587 C50.5476129,144.728587 58.1788152,137.097384 58.1788152,127.683191 C58.1788152,118.264493 50.5476129,110.63254 41.1334194,110.63254 L41.1334194,110.63254 Z M162.848282,188.111202 C154.694569,192.820551 151.898839,203.240727 156.608938,211.389935 C161.313032,219.543648 171.733208,222.338628 179.886921,217.629279 C188.039883,212.925185 190.835613,202.505009 186.126264,194.350545 C181.42217,186.202088 170.995988,183.407109 162.848282,188.111202 L162.848282,188.111202 Z M78.1618299,127.683191 C78.1618299,110.836739 86.5295015,95.9534545 99.3332551,86.9409032 L86.8703343,66.0667683 C71.9555191,76.0365044 60.8581818,91.271132 56.2464282,109.113806 C61.6276833,113.504845 65.0720469,120.189372 65.0720469,127.68244 C65.0720469,135.171003 61.6276833,141.855531 56.2464282,146.246569 C60.852176,164.094499 71.9495132,179.329877 86.8703343,189.299613 L99.3332551,168.420223 C86.5295015,159.412927 78.1618299,144.530393 78.1618299,127.683191 L78.1618299,127.683191 Z M127.954205,77.8855601 C153.967109,77.8855601 175.30895,97.8302874 177.549138,123.265877 L201.839859,122.907777 C200.644692,104.129689 192.441431,87.2719765 179.836622,74.875871 C173.354792,77.3247625 165.86773,76.9501466 159.396411,73.2197537 C152.91383,69.4788504 148.849361,63.1681877 147.738276,56.3177478 C141.438123,54.5790499 134.807648,53.6271202 127.952704,53.6271202 C116.168446,53.6271202 105.026815,56.3950733 95.1344047,61.2913548 L106.979472,82.5175836 C113.351695,79.5521877 120.460387,77.8855601 127.954205,77.8855601 L127.954205,77.8855601 Z M127.954205,177.475566 C120.460387,177.475566 113.351695,175.808188 106.980223,172.843543 L95.1351554,194.069021 C105.027566,198.971308 116.169196,201.740012 127.954205,201.740012 C134.80915,201.740012 141.439625,200.787331 147.739026,199.043378 C148.850111,192.192938 152.916082,185.888282 159.397161,182.140622 C165.872985,178.404223 173.355543,178.036364 179.837372,180.485255 C192.442182,168.08915 200.645443,151.231437 201.84061,132.453349 L177.543883,132.095249 C175.30895,157.537595 153.967859,177.475566 127.954205,177.475566 L127.954205,177.475566 Z M162.842276,67.2446686 C170.995988,71.9532669 181.416915,69.1642933 186.121009,61.0105806 C190.830358,52.856868 188.041384,42.4359413 179.886921,37.7258416 C171.733208,33.0217478 161.313032,35.8167273 156.602182,43.9704399 C151.898839,52.1196481 154.693818,62.5405748 162.842276,67.2446686 L162.842276,67.2446686 Z" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.1 KiB |
|
@ -1,200 +0,0 @@
|
|||
|
||||
|
||||
function JobViewModel(repo, build, job, status) {
|
||||
var self = this;
|
||||
self.status = status;
|
||||
|
||||
self.stream = function() {
|
||||
$("#output").html("");
|
||||
$("#restart").hide();
|
||||
$("#cancel").show();
|
||||
|
||||
var buf = new Drone.Buffer();
|
||||
buf.start(document.getElementById("output"));
|
||||
|
||||
$( "#tail" ).show();
|
||||
$( "#tail" ).click(function() {
|
||||
buf.autoFollow = !buf.autoFollow;
|
||||
if (buf.autoFollow) {
|
||||
$( "#tail i" ).text("pause");
|
||||
$( "#tail" ).show();
|
||||
|
||||
// scroll to the bottom of the page
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
} else {
|
||||
$( "#tail i" ).text("expand_more");
|
||||
$( "#tail" ).show();
|
||||
}
|
||||
})
|
||||
|
||||
Stream(repo, build, job, function(out){
|
||||
buf.write(out);
|
||||
});
|
||||
};
|
||||
|
||||
if (status !== "running" && status !== "pending") {
|
||||
Logs(repo, build, job);
|
||||
$("#restart").show();
|
||||
}
|
||||
|
||||
if (status === "running") {
|
||||
self.stream();
|
||||
}
|
||||
|
||||
$("#restart").click(function() {
|
||||
$("#restart").hide();
|
||||
$("#output").html("");
|
||||
$(".status").attr("class", "status pending").text("pending");
|
||||
|
||||
$.ajax({
|
||||
url: "/api/repos/"+repo+"/builds/"+build,
|
||||
type: "POST",
|
||||
success: function( data ) { },
|
||||
error: function( data ) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
$("#cancel").click(function() {
|
||||
$("#cancel").hide();
|
||||
|
||||
$.ajax({
|
||||
url: "/api/repos/"+repo+"/builds/"+build+"/"+job,
|
||||
type: "DELETE",
|
||||
success: function( data ) { },
|
||||
error: function( data ) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
Subscribe(repo, function(data){
|
||||
if (!data.jobs) {
|
||||
return;
|
||||
}
|
||||
if (data.number !== build) {
|
||||
return;
|
||||
}
|
||||
|
||||
var before = self.status;
|
||||
self.status = data.jobs[job-1].status;
|
||||
|
||||
// update the status for each job in the view
|
||||
for (var i=0;i<data.jobs.length;i++) {
|
||||
var job_ = data.jobs[i];
|
||||
var el = $("[data-job="+job_.number+"]");
|
||||
|
||||
el.find(".status")
|
||||
.attr("class", "status "+job_.status).text(job_.status);
|
||||
|
||||
switch (job_.status) {
|
||||
case "running":
|
||||
el.find(".msg-running").find("span").attr("data-livestamp", job_.started_at);
|
||||
|
||||
el.find(".msg-pending").hide();
|
||||
el.find(".msg-running").show();
|
||||
el.find(".msg-finished").hide();
|
||||
el.find(".msg-exited").hide();
|
||||
break;
|
||||
case "pending":
|
||||
el.find(".msg-pending").show();
|
||||
el.find(".msg-running").hide();
|
||||
el.find(".msg-finished").hide();
|
||||
el.find(".msg-exited").hide();
|
||||
break;
|
||||
default:
|
||||
el.find(".msg-finished").find("span").attr("data-livestamp", job_.finished_at);
|
||||
el.find(".msg-exited").find("span").text(job_.exit_code);
|
||||
|
||||
el.find(".msg-pending").hide();
|
||||
el.find(".msg-running").hide();
|
||||
el.find(".msg-finished").show();
|
||||
el.find(".msg-exited").show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var after = self.status;
|
||||
|
||||
// if the status has changed we should start
|
||||
// streaming the build contents.
|
||||
if (before !== after && after === "running") {
|
||||
self.stream();
|
||||
}
|
||||
|
||||
// if the status is changes to complete, we can show
|
||||
// the restart button and hide the tail button.
|
||||
if (after !== "pending" && after !== "running") {
|
||||
$("#restart").show();
|
||||
$("#cancel").hide();
|
||||
$("#tail").hide();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function Logs(repo, build, job) {
|
||||
|
||||
$.get( "/api/repos/"+repo+"/logs/"+build+"/"+job, function( data ) {
|
||||
|
||||
var lines = JSON.parse(data);
|
||||
|
||||
var groups = {}
|
||||
for (var i=0; i<lines.length; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
if (!line.proc) {
|
||||
continue
|
||||
}
|
||||
|
||||
var group = groups[line.proc];
|
||||
|
||||
if (!group) {
|
||||
|
||||
// create an element to hold the group of output
|
||||
var pre = $("<pre>").attr("data-title", line.proc);
|
||||
$("#output").append(pre);
|
||||
|
||||
// create the buffer for the group of output
|
||||
var buf = new Drone.Buffer();
|
||||
buf.start(pre[0]);
|
||||
|
||||
// add items to the group
|
||||
group = {
|
||||
pre: pre,
|
||||
buf: buf,
|
||||
};
|
||||
groups[line.proc]=group;
|
||||
}
|
||||
|
||||
group.buf.write(line.out+"\n");
|
||||
}
|
||||
|
||||
for (var i=0; i<groups.length; i++) {
|
||||
groups[i].buf.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function Stream(repo, build, job, _callback) {
|
||||
var callback = _callback;
|
||||
|
||||
var events = new EventSource("/api/stream/" + repo + "/" + build + "/" + job, {withCredentials: true});
|
||||
events.onmessage = function (event) {
|
||||
if (callback !== undefined) {
|
||||
callback(event.data);
|
||||
}
|
||||
};
|
||||
events.onerror = function (event) {
|
||||
callback = undefined;
|
||||
if (events !== undefined) {
|
||||
events.close();
|
||||
events = undefined;
|
||||
}
|
||||
console.log('user event stream closed due to error.', event);
|
||||
};
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
$(function () {
|
||||
|
||||
// fetch the CSRF token from the meta tag
|
||||
var token = $("meta[name='_csrf']").attr("content");
|
||||
|
||||
// ensure every Ajax request has the CSRF token
|
||||
// included in the request's header.
|
||||
$(document).ajaxSend(function(e, xhr, options) {
|
||||
xhr.setRequestHeader("X-CSRF-TOKEN", token);
|
||||
});
|
||||
});
|
|
@ -1,90 +0,0 @@
|
|||
/**
|
||||
* Creates an observable build job.
|
||||
*/
|
||||
function Job(data) {
|
||||
this.number = ko.observable(data.number);
|
||||
this.commit = ko.observable(data.commit);
|
||||
this.started_at = ko.observable(data.started_at);
|
||||
this.finished_at = ko.observable(data.finished_at);
|
||||
this.exit_code = ko.observable(data.exit_code);
|
||||
this.status = ko.observable(data.status);
|
||||
this.environment = ko.observable(data.environment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable build.
|
||||
*/
|
||||
function Build(data) {
|
||||
this.number = ko.observable(data.number);
|
||||
this.commit = ko.observable(data.commit);
|
||||
this.branch = ko.observable(data.branch);
|
||||
this.author = ko.observable(data.author);
|
||||
this.message = ko.observable(data.message);
|
||||
this.status = ko.observable(data.status);
|
||||
this.event = ko.observable(data.event);
|
||||
this.started_at = ko.observable(data.started_at);
|
||||
this.finished_at = ko.observable(data.finished_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable repository.
|
||||
*/
|
||||
function Repo(data) {
|
||||
this.full_name = ko.observable(data.full_name);
|
||||
this.owner = ko.observable(data.owner);
|
||||
this.name = ko.observable(data.name);
|
||||
this.private = ko.observable(data.private);
|
||||
this.trusted = ko.observable(data.trusted);
|
||||
this.timeout = ko.observable(data.timeout);
|
||||
this.avatar_url = ko.observable(data.avatar_url);
|
||||
this.clone_url = ko.observable(data.clone_url);
|
||||
this.link_url = ko.observable(data.link_url);
|
||||
this.starred = ko.observable(data.starred || false);
|
||||
this.events = ko.observable(data.events);
|
||||
this.hook = ko.observable(new Hook(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two repository objects by name. Used to sort
|
||||
* a list of repositories.
|
||||
*/
|
||||
function RepoCompare(a, b) {
|
||||
return a.full_name().toLowerCase() > b.full_name().toLowerCase() ? 1 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable object that stores a list of hook event
|
||||
* types (push, pull request, etc) and true or false if enabled.
|
||||
*/
|
||||
function Hook(repo) {
|
||||
var data = {
|
||||
"pull_request" : repo.events.indexOf("pull_request") !== -1,
|
||||
"push" : repo.events.indexOf("push") !== -1,
|
||||
"tag" : repo.events.indexOf("tag") !== -1,
|
||||
"deploy" : repo.events.indexOf("deploy") !== -1
|
||||
};
|
||||
|
||||
this.pull_request = ko.observable(data.pull_request);
|
||||
this.push = ko.observable(data.push);
|
||||
this.tag = ko.observable(data.tag);
|
||||
this.deploy = ko.observable(data.deploy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable user.
|
||||
*/
|
||||
function User(data) {
|
||||
this.login = ko.observable(data.login);
|
||||
this.email = ko.observable(data.email);
|
||||
this.avatar_url = ko.observable(data.avatar_url);
|
||||
this.active = ko.observable(data.active);
|
||||
this.admin = ko.observable(data.admin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two user objects by login. Used to sort
|
||||
* a list of users.
|
||||
*/
|
||||
function UserCompare(a, b) {
|
||||
return a.login().toLowerCase() > b.login().toLowerCase() ? 1 : -1;
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
|
||||
function NodeViewModel() {
|
||||
var self = this;
|
||||
|
||||
// handle requests to create a new node.
|
||||
$(".modal-node button").click(function(e) {
|
||||
|
||||
var node = {
|
||||
address : $("#addr").val(),
|
||||
key : $("#key").val(),
|
||||
cert : $("#cert").val(),
|
||||
ca : $("#ca").val()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: "/api/nodes",
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(node),
|
||||
success: function( data ) {
|
||||
// clears the form value
|
||||
$(".modal-node input").val("");
|
||||
|
||||
var el = $("<div>").attr("class", "col-sm-4").append(
|
||||
$("<div>").attr("class", "card").attr("data-id", data.id).append(
|
||||
$("<div>").attr("class", "card-header").append(
|
||||
$("<i>").attr("class", "linux_amd64")
|
||||
)
|
||||
).append(
|
||||
$("<div>").attr("class", "card-block").append(
|
||||
$("<h3>").text(data.address)
|
||||
).append(
|
||||
$("<p>").attr("class", "card-text").text(data.architecture)
|
||||
).append(
|
||||
$("<div>").attr("class", "btn-group").append(
|
||||
$("<button>").attr("class","btn btn-danger").text("Delete")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
$( ".node-row" ).prepend(el);
|
||||
},
|
||||
error: function( data ) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$(".node-row").on('click', '.btn-group .btn-danger', function(){
|
||||
// gets the unique identifier for the click row, which is
|
||||
// the user login id.
|
||||
var id = $( this ).context
|
||||
.parentNode
|
||||
.parentNode
|
||||
.parentNode.dataset.id;
|
||||
|
||||
var r = confirm("Are you sure you want to delete node "+id+"?");
|
||||
if (r === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// makes an API call to delete the user and then, if successful,
|
||||
// removes from the list.
|
||||
$.ajax({
|
||||
url: "/api/nodes/"+id,
|
||||
type: "DELETE",
|
||||
success: function( data ) {
|
||||
$("[data-id='"+id+"']").parent().remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
|
||||
|
||||
|
||||
function RepoViewModel(repo) {
|
||||
var self = this;
|
||||
|
||||
Subscribe(repo, function(data){
|
||||
var el = $("[data-build="+data.number+"]");
|
||||
|
||||
if (el && el.length !== 0) {
|
||||
// find the status label and adjust the
|
||||
// build status accordingly.
|
||||
var status = el.find(".status");
|
||||
status.attr("class", "status "+data.status);
|
||||
status.text(data.status);
|
||||
return
|
||||
}
|
||||
|
||||
// construct the build entry if it doesn't already exist
|
||||
// so that we can append to the DOM. The code may not be
|
||||
// pretty, but it is simple enough and it works.
|
||||
var authoredOrDeployed = "authored"
|
||||
var branchOrDeploy = data.branch
|
||||
if ( data.event == "deployment" ) {
|
||||
authoredOrDeployed = "deployed"
|
||||
branchOrDeploy = data.deploy_to
|
||||
}
|
||||
|
||||
el = $("<a>").attr("class", "card").attr("href", "/"+repo+"/"+data.number).attr("data-build", data.number)
|
||||
.append(
|
||||
$("<div>").attr("class", "card-header").append(
|
||||
$("<img>").attr("src", data.author_avatar)
|
||||
)
|
||||
)
|
||||
.append(
|
||||
$("<div>").attr("class", "card-block").append(
|
||||
$("<div>").append(
|
||||
$("<div>").attr("class", "status "+ data.status).text(data.status)
|
||||
).append(
|
||||
$("<h3>").text(data.message)
|
||||
)
|
||||
).append(
|
||||
$("<p>").attr("class","card-text").append(
|
||||
$("<em>").text(data.author)
|
||||
).append(
|
||||
$("<span>").text(authoredOrDeployed)
|
||||
).append(
|
||||
$("<em>").attr("data-livestamp", data.created_at)
|
||||
).append(
|
||||
$("<span>").text("to")
|
||||
).append(
|
||||
$("<em>").text(branchOrDeploy)
|
||||
)
|
||||
)
|
||||
).css("display", "flex").hide().fadeIn(1000);
|
||||
|
||||
// TODO it is very possible that the group may not
|
||||
// exist, in which case the we'll need to create the
|
||||
// gropu as well.
|
||||
|
||||
// append to the latest group in the timeline.
|
||||
$(".card").first().before(el);
|
||||
});
|
||||
}
|
||||
|
||||
function Subscribe(repo, _callback) {
|
||||
var callback = _callback;
|
||||
|
||||
var events = new EventSource("/api/stream/" + repo, {withCredentials: true});
|
||||
events.onmessage = function (event) {
|
||||
if (callback !== undefined) {
|
||||
callback(JSON.parse(event.data));
|
||||
}
|
||||
};
|
||||
|
||||
events.onerror = function (event) {
|
||||
callback = undefined;
|
||||
if (events !== undefined) {
|
||||
events.close();
|
||||
events = undefined;
|
||||
}
|
||||
console.log('user event stream closed due to error.', event);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
function RepoConfigViewModel(repo) {
|
||||
var self = this;
|
||||
|
||||
var timeoutLabel = $(".timeout-label")
|
||||
|
||||
$("input[type='range']").change(function(e) {
|
||||
var timeout = parseInt(e.target.value);
|
||||
timeoutLabel.text(timeout + " minutes");
|
||||
patchRepo(repo, { timeout: timeout })
|
||||
})
|
||||
|
||||
$("#push").change(function(e) {
|
||||
patchRepo(repo, {
|
||||
allow_push: e.target.checked,
|
||||
})
|
||||
})
|
||||
|
||||
$("#pull").change(function(e) {
|
||||
patchRepo(repo, {
|
||||
allow_pr: e.target.checked,
|
||||
})
|
||||
})
|
||||
|
||||
$("#tag").change(function(e) {
|
||||
patchRepo(repo, {
|
||||
allow_tag: e.target.checked,
|
||||
})
|
||||
})
|
||||
|
||||
$("#deploy").change(function(e) {
|
||||
patchRepo(repo, {
|
||||
allow_deploy: e.target.checked,
|
||||
})
|
||||
})
|
||||
|
||||
$("#trusted").change(function(e) {
|
||||
patchRepo(repo, {
|
||||
trusted: e.target.checked,
|
||||
})
|
||||
})
|
||||
|
||||
$(".btn-danger").click(function(e) {
|
||||
var r = confirm("Are you sure you want to delete this repository?");
|
||||
if (r !== false) {
|
||||
deleteRepo(repo);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function deleteRepo(repo) {
|
||||
$.ajax({
|
||||
url: "/api/repos/"+repo,
|
||||
type: "DELETE",
|
||||
contentType: "application/json",
|
||||
success: function() {
|
||||
window.location.href="/";
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function patchRepo(repo, data) {
|
||||
$.ajax({
|
||||
url: "/api/repos/"+repo,
|
||||
type: "PATCH",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data)
|
||||
});
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
function RepoListViewModel(repos) {
|
||||
var self = this;
|
||||
|
||||
var mapped = $.map(repos, function(repo) {
|
||||
return new Repo(repo)
|
||||
});
|
||||
|
||||
self.repos = ko.observableArray(mapped);
|
||||
self.newRepo = ko.observable();
|
||||
|
||||
self.addRepo = function() {
|
||||
$.ajax({
|
||||
url: "/api/repos/"+self.newRepo(),
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
success: function( data ) {
|
||||
self.repos.push(new Repo(data));
|
||||
self.repos.sort(RepoCompare);
|
||||
self.newRepo("");
|
||||
},
|
||||
error: function( data ) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
var repoExpr = /.+\/.+/;
|
||||
|
||||
var remoteRepos = new Bloodhound({
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace("full_name"),
|
||||
|
||||
identify: function(obj) { return obj.full_name; },
|
||||
prefetch: '/api/user/repos/remote'
|
||||
});
|
||||
|
||||
|
||||
function reposWithDefaults(q, sync) {
|
||||
if (q === "") {
|
||||
sync(remoteRepos.all())
|
||||
} else {
|
||||
remoteRepos.search(q, sync);
|
||||
}
|
||||
}
|
||||
|
||||
$('.typeahead').typeahead({
|
||||
hint: true,
|
||||
highlight: true,
|
||||
minLength: 0
|
||||
},
|
||||
{
|
||||
name: "repos",
|
||||
display: "full_name",
|
||||
source: reposWithDefaults,
|
||||
templates: {
|
||||
empty: function(obj) {
|
||||
if (obj.query.match(repoExpr) !== null) {
|
||||
return [
|
||||
"<div>",
|
||||
"<div class='not-indexed-message'>",
|
||||
"<p>",
|
||||
"No matches found for",
|
||||
"<em>",
|
||||
obj.query,
|
||||
"</em>",
|
||||
"</p>",
|
||||
"<p>",
|
||||
"This repository may not be indexed yet.",
|
||||
"<a href='/"+obj.query+"'>",
|
||||
"Click here",
|
||||
"</a>",
|
||||
"to visit this repository page directly.",
|
||||
"</p>",
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("\n");
|
||||
}
|
||||
return [
|
||||
"<div>",
|
||||
"<div class='no-matches-message'>",
|
||||
"No matches found",
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("\n");
|
||||
},
|
||||
suggestion: function(obj) {
|
||||
return "<div><div><img src='"+obj.avatar_url+"' width='32px' height='32px' /></div><div>"+ obj.full_name +"</div></div>";
|
||||
}
|
||||
}
|
||||
}).bind('typeahead:select', function(ev, suggestion) {
|
||||
window.location.href="/"+suggestion.full_name;
|
||||
});
|
|
@ -1,397 +0,0 @@
|
|||
var Filter, STYLES, defaults, entities, extend, toHexString, _i, _results,
|
||||
__slice = [].slice;
|
||||
|
||||
// theme stuff:
|
||||
// http://ciembor.github.io/4bit
|
||||
// https://github.com/lysyi3m/osx-terminal-themes
|
||||
|
||||
STYLES = {
|
||||
'ef0': 'color:#000',
|
||||
'ef1': 'color:#b87a7a',
|
||||
'ef2': 'color:#7ab87a',
|
||||
'ef3': 'color:#b8b87a',
|
||||
'ef4': 'color:#7a7ab8',
|
||||
'ef5': 'color:#b87ab8',
|
||||
'ef6': 'color:#7ab8b8',
|
||||
'ef7': 'color:#d9d9d9',
|
||||
'ef8': 'color:#262626',
|
||||
'ef9': 'color:#dbbdbd',
|
||||
'ef10': 'color:#bddbbd',
|
||||
'ef11': 'color:#dbdbbd',
|
||||
'ef12': 'color:#bdbddb',
|
||||
'ef13': 'color:#dbbddb',
|
||||
'ef14': 'color:#bddbdb',
|
||||
'ef15': 'color:#FFF',
|
||||
'eb0': 'background-color:#000',
|
||||
'eb1': 'background-color:#b87a7a',
|
||||
'eb2': 'background-color:#7ab87a',
|
||||
'eb3': 'background-color:#b8b87a',
|
||||
'eb4': 'background-color:#7a7ab8',
|
||||
'eb5': 'background-color:#b87ab8',
|
||||
'eb6': 'background-color:#7ab8b8',
|
||||
'eb7': 'background-color:#d9d9d9',
|
||||
'eb8': 'background-color:#262626',
|
||||
'eb9': 'background-color:#dbbdbd',
|
||||
'eb10': 'background-color:#bddbbd',
|
||||
'eb11': 'background-color:#dbdbbd',
|
||||
'eb12': 'background-color:#bdbddb',
|
||||
'eb13': 'background-color:#dbbddb',
|
||||
'eb14': 'background-color:#bddbdb',
|
||||
'eb15': 'background-color:#FFF'
|
||||
};
|
||||
|
||||
toHexString = function(num) {
|
||||
num = num.toString(16);
|
||||
while (num.length < 2) {
|
||||
num = "0" + num;
|
||||
}
|
||||
return num;
|
||||
};
|
||||
|
||||
[0, 1, 2, 3, 4, 5].forEach(function(red) {
|
||||
return [0, 1, 2, 3, 4, 5].forEach(function(green) {
|
||||
return [0, 1, 2, 3, 4, 5].forEach(function(blue) {
|
||||
var b, c, g, n, r, rgb;
|
||||
c = 16 + (red * 36) + (green * 6) + blue;
|
||||
r = red > 0 ? red * 40 + 55 : 0;
|
||||
g = green > 0 ? green * 40 + 55 : 0;
|
||||
b = blue > 0 ? blue * 40 + 55 : 0;
|
||||
rgb = ((function() {
|
||||
var _i, _len, _ref, _results;
|
||||
_ref = [r, g, b];
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
n = _ref[_i];
|
||||
_results.push(toHexString(n));
|
||||
}
|
||||
return _results;
|
||||
})()).join('');
|
||||
STYLES["ef" + c] = "color:#" + rgb;
|
||||
return STYLES["eb" + c] = "background-color:#" + rgb;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
(function() {
|
||||
_results = [];
|
||||
for (_i = 0; _i <= 23; _i++){ _results.push(_i); }
|
||||
return _results;
|
||||
}).apply(this).forEach(function(gray) {
|
||||
var c, l;
|
||||
c = gray + 232;
|
||||
l = toHexString(gray * 10 + 8);
|
||||
STYLES["ef" + c] = "color:#" + l + l + l;
|
||||
return STYLES["eb" + c] = "background-color:#" + l + l + l;
|
||||
});
|
||||
|
||||
extend = function() {
|
||||
var dest, k, obj, objs, v, _j, _len;
|
||||
dest = arguments[0], objs = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
||||
for (_j = 0, _len = objs.length; _j < _len; _j++) {
|
||||
obj = objs[_j];
|
||||
for (k in obj) {
|
||||
v = obj[k];
|
||||
dest[k] = v;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
};
|
||||
|
||||
defaults = {
|
||||
fg: '#FFF',
|
||||
bg: '#000',
|
||||
newline: false,
|
||||
escapeXML: false,
|
||||
stream: false
|
||||
};
|
||||
|
||||
Filter = (function() {
|
||||
function Filter(options) {
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
this.opts = extend({}, defaults, options);
|
||||
this.input = [];
|
||||
this.stack = [];
|
||||
this.stickyStack = [];
|
||||
}
|
||||
|
||||
Filter.prototype.toHtml = function(input) {
|
||||
var buf;
|
||||
this.input = typeof input === 'string' ? [input] : input;
|
||||
buf = [];
|
||||
this.stickyStack.forEach((function(_this) {
|
||||
return function(element) {
|
||||
return _this.generateOutput(element.token, element.data, function(chunk) {
|
||||
return buf.push(chunk);
|
||||
});
|
||||
};
|
||||
})(this));
|
||||
this.forEach(function(chunk) {
|
||||
return buf.push(chunk);
|
||||
});
|
||||
this.input = [];
|
||||
return buf.join('');
|
||||
};
|
||||
|
||||
Filter.prototype.forEach = function(callback) {
|
||||
var buf;
|
||||
buf = '';
|
||||
this.input.forEach((function(_this) {
|
||||
return function(chunk) {
|
||||
buf += chunk;
|
||||
return _this.tokenize(buf, function(token, data) {
|
||||
_this.generateOutput(token, data, callback);
|
||||
if (_this.opts.stream) {
|
||||
return _this.updateStickyStack(token, data);
|
||||
}
|
||||
});
|
||||
};
|
||||
})(this));
|
||||
if (this.stack.length) {
|
||||
return callback(this.resetStyles());
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.generateOutput = function(token, data, callback) {
|
||||
switch (token) {
|
||||
case 'text':
|
||||
return callback(this.pushText(data));
|
||||
case 'display':
|
||||
return this.handleDisplay(data, callback);
|
||||
case 'xterm256':
|
||||
return callback(this.pushStyle("ef" + data));
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.updateStickyStack = function(token, data) {
|
||||
var notCategory;
|
||||
notCategory = function(category) {
|
||||
return function(e) {
|
||||
return (category === null || e.category !== category) && category !== 'all';
|
||||
};
|
||||
};
|
||||
if (token !== 'text') {
|
||||
this.stickyStack = this.stickyStack.filter(notCategory(this.categoryForCode(data)));
|
||||
return this.stickyStack.push({
|
||||
token: token,
|
||||
data: data,
|
||||
category: this.categoryForCode(data)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.handleDisplay = function(code, callback) {
|
||||
code = parseInt(code, 10);
|
||||
if (code === -1) {
|
||||
callback('<br/>');
|
||||
}
|
||||
if (code === 0) {
|
||||
if (this.stack.length) {
|
||||
callback(this.resetStyles());
|
||||
}
|
||||
}
|
||||
if (code === 1) {
|
||||
callback(this.pushTag('b'));
|
||||
}
|
||||
if (code === 2) {
|
||||
|
||||
}
|
||||
if ((2 < code && code < 5)) {
|
||||
callback(this.pushTag('u'));
|
||||
}
|
||||
if ((4 < code && code < 7)) {
|
||||
callback(this.pushTag('blink'));
|
||||
}
|
||||
if (code === 7) {
|
||||
|
||||
}
|
||||
if (code === 8) {
|
||||
callback(this.pushStyle('display:none'));
|
||||
}
|
||||
if (code === 9) {
|
||||
callback(this.pushTag('strike'));
|
||||
}
|
||||
if (code === 24) {
|
||||
callback(this.closeTag('u'));
|
||||
}
|
||||
if ((29 < code && code < 38)) {
|
||||
callback(this.pushStyle("ef" + (code - 30)));
|
||||
}
|
||||
if (code === 39) {
|
||||
callback(this.pushStyle("color:" + this.opts.fg));
|
||||
}
|
||||
if ((39 < code && code < 48)) {
|
||||
callback(this.pushStyle("eb" + (code - 40)));
|
||||
}
|
||||
if (code === 49) {
|
||||
callback(this.pushStyle("background-color:" + this.opts.bg));
|
||||
}
|
||||
if ((89 < code && code < 98)) {
|
||||
callback(this.pushStyle("ef" + (8 + (code - 90))));
|
||||
}
|
||||
if ((99 < code && code < 108)) {
|
||||
return callback(this.pushStyle("eb" + (8 + (code - 100))));
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.categoryForCode = function(code) {
|
||||
code = parseInt(code, 10);
|
||||
if (code === 0) {
|
||||
return 'all';
|
||||
} else if (code === 1) {
|
||||
return 'bold';
|
||||
} else if ((2 < code && code < 5)) {
|
||||
return 'underline';
|
||||
} else if ((4 < code && code < 7)) {
|
||||
return 'blink';
|
||||
} else if (code === 8) {
|
||||
return 'hide';
|
||||
} else if (code === 9) {
|
||||
return 'strike';
|
||||
} else if ((29 < code && code < 38) || code === 39 || (89 < code && code < 98)) {
|
||||
return 'foreground-color';
|
||||
} else if ((39 < code && code < 48) || code === 49 || (99 < code && code < 108)) {
|
||||
return 'background-color';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.pushTag = function(tag, style) {
|
||||
if (style == null) {
|
||||
style = '';
|
||||
}
|
||||
if (style.length && style.indexOf(':') === -1) {
|
||||
style = STYLES[style];
|
||||
}
|
||||
this.stack.push(tag);
|
||||
return ["<" + tag, (style ? " style=\"" + style + "\"" : void 0), ">"].join('');
|
||||
};
|
||||
|
||||
Filter.prototype.pushText = function(text) {
|
||||
if (this.opts.escapeXML) {
|
||||
return entities.encodeXML(text);
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.pushStyle = function(style) {
|
||||
return this.pushTag("span", style);
|
||||
};
|
||||
|
||||
Filter.prototype.closeTag = function(style) {
|
||||
var last;
|
||||
if (this.stack.slice(-1)[0] === style) {
|
||||
last = this.stack.pop();
|
||||
}
|
||||
if (last != null) {
|
||||
return "</" + style + ">";
|
||||
}
|
||||
};
|
||||
|
||||
Filter.prototype.resetStyles = function() {
|
||||
var stack, _ref;
|
||||
_ref = [this.stack, []], stack = _ref[0], this.stack = _ref[1];
|
||||
return stack.reverse().map(function(tag) {
|
||||
return "</" + tag + ">";
|
||||
}).join('');
|
||||
};
|
||||
|
||||
Filter.prototype.tokenize = function(text, callback) {
|
||||
var ansiHandler, ansiMatch, ansiMess, handler, i, length, newline, process, realText, remove, removeXterm256, tokens, _j, _len, _results1;
|
||||
ansiMatch = false;
|
||||
ansiHandler = 3;
|
||||
remove = function(m) {
|
||||
return '';
|
||||
};
|
||||
removeXterm256 = function(m, g1) {
|
||||
callback('xterm256', g1);
|
||||
return '';
|
||||
};
|
||||
newline = (function(_this) {
|
||||
return function(m) {
|
||||
if (_this.opts.newline) {
|
||||
callback('display', -1);
|
||||
} else {
|
||||
callback('text', m);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
})(this);
|
||||
ansiMess = function(m, g1) {
|
||||
var code, _j, _len;
|
||||
ansiMatch = true;
|
||||
if (g1.trim().length === 0) {
|
||||
g1 = '0';
|
||||
}
|
||||
g1 = g1.trimRight(';').split(';');
|
||||
for (_j = 0, _len = g1.length; _j < _len; _j++) {
|
||||
code = g1[_j];
|
||||
callback('display', code);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
realText = function(m) {
|
||||
callback('text', m);
|
||||
return '';
|
||||
};
|
||||
tokens = [
|
||||
{
|
||||
pattern: /^\x08+/,
|
||||
sub: remove
|
||||
}, {
|
||||
pattern: /^\x1b\[[012]?K/,
|
||||
sub: remove
|
||||
}, {
|
||||
pattern: /^\x1b\[38;5;(\d+)m/,
|
||||
sub: removeXterm256
|
||||
}, {
|
||||
pattern: /^\n+/,
|
||||
sub: newline
|
||||
}, {
|
||||
pattern: /^\r+/,
|
||||
sub: newline
|
||||
}, {
|
||||
pattern: /^\x1b\[((?:\d{1,3};?)+|)m/,
|
||||
sub: ansiMess
|
||||
}, {
|
||||
pattern: /^\x1b\[?[\d;]{0,3}/,
|
||||
sub: remove
|
||||
}, {
|
||||
pattern: /^([^\x1b\x08\n]+)/,
|
||||
sub: realText
|
||||
}
|
||||
];
|
||||
process = function(handler, i) {
|
||||
var matches;
|
||||
if (i > ansiHandler && ansiMatch) {
|
||||
return;
|
||||
} else {
|
||||
ansiMatch = false;
|
||||
}
|
||||
matches = text.match(handler.pattern);
|
||||
text = text.replace(handler.pattern, handler.sub);
|
||||
if (matches == null) {
|
||||
|
||||
}
|
||||
};
|
||||
_results1 = [];
|
||||
while ((length = text.length) > 0) {
|
||||
for (i = _j = 0, _len = tokens.length; _j < _len; i = ++_j) {
|
||||
handler = tokens[i];
|
||||
process(handler, i);
|
||||
}
|
||||
if (text.length === length) {
|
||||
break;
|
||||
} else {
|
||||
_results1.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results1;
|
||||
};
|
||||
|
||||
return Filter;
|
||||
|
||||
})();
|
|
@ -1,52 +0,0 @@
|
|||
;// Live commit updates
|
||||
|
||||
if(typeof(Drone) === 'undefined') { Drone = {}; }
|
||||
|
||||
(function () {
|
||||
Drone.Buffer = function() {
|
||||
this.lineFormatter = new Filter({stream: true, newline: false});
|
||||
}
|
||||
|
||||
Drone.Buffer.prototype = {
|
||||
lineBuffer: "",
|
||||
autoFollow: false,
|
||||
stoppingRefresh: false,
|
||||
|
||||
start: function(el) {
|
||||
if(typeof(el) === 'string') {
|
||||
this.el = document.getElementById(el);
|
||||
} else {
|
||||
this.el = el;
|
||||
}
|
||||
|
||||
this.el.innerHTML="";
|
||||
this.update();
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this.stoppingRefresh = true;
|
||||
},
|
||||
|
||||
update: function() {
|
||||
if(this.lineBuffer.length > 0) {
|
||||
this.el.innerHTML += this.lineFormatter.toHtml(escapeHTML(this.lineBuffer));
|
||||
this.lineBuffer = '';
|
||||
|
||||
if (this.autoFollow) {
|
||||
window.scrollTo(0, document.body.scrollHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.stoppingRefresh) {
|
||||
this.stoppingRefresh = false;
|
||||
} else {
|
||||
window.requestAnimationFrame(this.update.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
write: function(data) {
|
||||
this.lineBuffer += data;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
|
@ -1,78 +0,0 @@
|
|||
|
||||
function UserViewModel() {
|
||||
var self = this;
|
||||
|
||||
// handle requests to create a new user.
|
||||
$(".modal-user button").click(function(e) {
|
||||
var login = $(".modal-user input").val();
|
||||
var user = { login: login };
|
||||
|
||||
$(".alert-danger").hide();
|
||||
|
||||
$.ajax({
|
||||
url: "/api/users",
|
||||
type: "POST",
|
||||
data: JSON.stringify(user),
|
||||
contentType: "application/json",
|
||||
success: function( data ) {
|
||||
// clears the form value
|
||||
$(".modal-user input").val("");
|
||||
|
||||
// find an existing item in the list and clone it.
|
||||
var el = $(".col-sm-4").first().clone();
|
||||
el.find("img").attr("src", data.avatar_url);
|
||||
el.find("h3").text(data.login);
|
||||
el.find("p").text(data.email);
|
||||
el.find(".card").attr("data-id", data.login);
|
||||
el.find(".card").attr("data-admin", data.admin);
|
||||
|
||||
$( ".user-row" ).prepend(el);
|
||||
},
|
||||
error: function(data) {
|
||||
$(".alert-danger").text(data.responseText);
|
||||
$(".alert-danger").show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$(".user-row").on('click', '.btn-group .btn-info', function(){
|
||||
// gets the unique identifier for the click row, which is
|
||||
// the user login id.
|
||||
var row = $( this ).closest("[data-id]");
|
||||
var id = row.data("id");
|
||||
var admin = row.data("admin") == true;
|
||||
|
||||
row.attr("data-admin", !admin);
|
||||
|
||||
$.ajax({
|
||||
url: "/api/users/"+id,
|
||||
type: "PATCH",
|
||||
data: JSON.stringify({active:true, admin: !admin}),
|
||||
contentType: "application/json"
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(".user-row").on('click', '.btn-group .btn-danger', function(){
|
||||
// gets the unique identifier for the click row, which is
|
||||
// the user login id.
|
||||
var row = $( this ).closest("[data-id]");
|
||||
var id = row.data("id");
|
||||
|
||||
var r = confirm("Are you sure you want to delete "+id+"?");
|
||||
if (r === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// makes an API call to delete the user and then, if successful,
|
||||
// removes from the list.
|
||||
$.ajax({
|
||||
url: "/api/users/"+id,
|
||||
type: "DELETE",
|
||||
success: function( data ) {
|
||||
row.parent().remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
Array.prototype.remove = function() {
|
||||
var what, a = arguments, L = a.length, ax;
|
||||
while (L && this.length) {
|
||||
what = a[--L];
|
||||
while ((ax = this.indexOf(what)) !== -1) {
|
||||
this.splice(ax, 1);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
function escapeHTML(html) {
|
||||
return document.createElement('div').appendChild(
|
||||
document.createTextNode(html)).parentNode.innerHTML;
|
||||
}
|
138
static/scripts/vendor/livestamp.js
vendored
|
@ -1,138 +0,0 @@
|
|||
// Livestamp.js / v2.0.0 / (c) 2015 Matt Bradley / MIT License
|
||||
(function (plugin) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery', 'moment'], plugin);
|
||||
} else {
|
||||
// Browser globals
|
||||
plugin(jQuery, moment);
|
||||
}
|
||||
}(function($, moment) {
|
||||
var updateInterval = 1e3,
|
||||
paused = false,
|
||||
$livestamps = $([]),
|
||||
|
||||
init = function() {
|
||||
livestampGlobal.resume();
|
||||
},
|
||||
|
||||
prep = function($el, timestamp) {
|
||||
var oldData = $el.data('livestampdata');
|
||||
if (typeof timestamp == 'number')
|
||||
timestamp *= 1e3;
|
||||
|
||||
$el.removeAttr('data-livestamp')
|
||||
.removeData('livestamp');
|
||||
|
||||
timestamp = moment(timestamp);
|
||||
if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
|
||||
var newData = $.extend({ }, { 'original': $el.contents() }, oldData);
|
||||
newData.moment = moment(timestamp);
|
||||
|
||||
$el.data('livestampdata', newData).empty();
|
||||
$livestamps.push($el[0]);
|
||||
}
|
||||
},
|
||||
|
||||
run = function() {
|
||||
if (paused) return;
|
||||
livestampGlobal.update();
|
||||
setTimeout(run, updateInterval);
|
||||
},
|
||||
|
||||
livestampGlobal = {
|
||||
update: function() {
|
||||
$('[data-livestamp]').each(function() {
|
||||
var $this = $(this);
|
||||
prep($this, $this.data('livestamp'));
|
||||
});
|
||||
|
||||
var toRemove = [];
|
||||
$livestamps.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('livestampdata');
|
||||
|
||||
if (data === undefined)
|
||||
toRemove.push(this);
|
||||
else if (moment.isMoment(data.moment)) {
|
||||
var from = $this.html(),
|
||||
to = data.moment.fromNow();
|
||||
|
||||
if (from != to) {
|
||||
var e = $.Event('change.livestamp');
|
||||
$this.trigger(e, [from, to]);
|
||||
if (!e.isDefaultPrevented())
|
||||
$this.html(to);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$livestamps = $livestamps.not(toRemove);
|
||||
delete $livestamps.prevObject
|
||||
},
|
||||
|
||||
pause: function() {
|
||||
paused = true;
|
||||
},
|
||||
|
||||
resume: function() {
|
||||
paused = false;
|
||||
run();
|
||||
},
|
||||
|
||||
interval: function(interval) {
|
||||
if (interval === undefined)
|
||||
return updateInterval;
|
||||
updateInterval = interval;
|
||||
}
|
||||
},
|
||||
|
||||
livestampLocal = {
|
||||
add: function($el, timestamp) {
|
||||
if (typeof timestamp == 'number')
|
||||
timestamp *= 1e3;
|
||||
timestamp = moment(timestamp);
|
||||
|
||||
if (moment.isMoment(timestamp) && !isNaN(+timestamp)) {
|
||||
$el.each(function() {
|
||||
prep($(this), timestamp);
|
||||
});
|
||||
livestampGlobal.update();
|
||||
}
|
||||
|
||||
return $el;
|
||||
},
|
||||
|
||||
destroy: function($el) {
|
||||
$livestamps = $livestamps.not($el);
|
||||
$el.each(function() {
|
||||
var $this = $(this),
|
||||
data = $this.data('livestampdata');
|
||||
|
||||
if (data === undefined)
|
||||
return $el;
|
||||
|
||||
$this
|
||||
.html(data.original ? data.original : '')
|
||||
.removeData('livestampdata');
|
||||
});
|
||||
|
||||
return $el;
|
||||
},
|
||||
|
||||
isLivestamp: function($el) {
|
||||
return $el.data('livestampdata') !== undefined;
|
||||
}
|
||||
};
|
||||
|
||||
$.livestamp = livestampGlobal;
|
||||
$(init);
|
||||
$.fn.livestamp = function(method, options) {
|
||||
if (!livestampLocal[method]) {
|
||||
options = method;
|
||||
method = 'add';
|
||||
}
|
||||
|
||||
return livestampLocal[method](this, options);
|
||||
};
|
||||
}));
|
666
static/scripts/vendor/plates.js
vendored
|
@ -1,666 +0,0 @@
|
|||
var Plates = (typeof module !== 'undefined' && 'id' in module && typeof exports !== 'undefined') ? exports : {};
|
||||
|
||||
!function(exports, env, undefined) {
|
||||
"use strict";
|
||||
|
||||
//
|
||||
// Cache variables to increase lookup speed.
|
||||
//
|
||||
var _toString = Object.prototype.toString;
|
||||
|
||||
//
|
||||
// Polyfill the Array#indexOf method for cross browser compatibility.
|
||||
//
|
||||
[].indexOf || (Array.prototype.indexOf = function indexOf(a, b ,c){
|
||||
for (
|
||||
c = this.length , b = (c+ ~~b) % c;
|
||||
b < c && (!(b in this) || this[b] !==a );
|
||||
b++
|
||||
);
|
||||
|
||||
return b^c ? b : -1;
|
||||
});
|
||||
|
||||
//
|
||||
// Polyfill Array.isArray for cross browser compatibility.
|
||||
//
|
||||
Array.isArray || (Array.isArray = function isArray(a) {
|
||||
return _toString.call(a) === '[object Array]';
|
||||
});
|
||||
|
||||
//
|
||||
// ### function fetch(data, mapping, value, key)
|
||||
// #### @data {Object} the data that we need to fetch a value from
|
||||
// #### @mapping {Object} The iterated mapping step
|
||||
// #### @tagbody {String} the tagbody we operated against
|
||||
// #### @key {String} optional key if the mapping doesn't have a dataKey
|
||||
// Fetches the correct piece of data
|
||||
//
|
||||
function fetch(data, mapping, value, tagbody, key) {
|
||||
key = mapping.dataKey || key;
|
||||
|
||||
//
|
||||
// Check if we have data manipulation or filtering function.
|
||||
//
|
||||
if (mapping.dataKey && typeof mapping.dataKey === 'function') {
|
||||
return mapping.dataKey(data, value || '', tagbody || '', key);
|
||||
}
|
||||
|
||||
//
|
||||
// See if we are using dot notation style
|
||||
//
|
||||
if (!~key.indexOf('.')) return data[key];
|
||||
|
||||
var result = key
|
||||
, structure = data;
|
||||
|
||||
for (var paths = key.split('.'), i = 0, length = paths.length; i < length && structure; i++) {
|
||||
result = structure[+paths[i] || paths[i]];
|
||||
structure = result;
|
||||
}
|
||||
|
||||
return result !== undefined ? result : data[key];
|
||||
}
|
||||
|
||||
//
|
||||
// compileMappings
|
||||
//
|
||||
// sort the mappings so that mappings for the same attribute and value go consecutive
|
||||
// and inside those, those that change attributes appear first.
|
||||
//
|
||||
function compileMappings(oldMappings) {
|
||||
var mappings = oldMappings.slice(0);
|
||||
|
||||
mappings.sort(function(map1, map2) {
|
||||
if (!map1.attribute) return 1;
|
||||
if (!map2.attribute) return -1;
|
||||
|
||||
if (map1.attribute !== map2.attribute) {
|
||||
return map1.attribute < map2.attribute ? -1 : 1;
|
||||
}
|
||||
if (map1.value !== map2.value) {
|
||||
return map1.value < map2.value ? -1 : 1;
|
||||
}
|
||||
if (! ('replace' in map1) && ! ('replace' in map2)) {
|
||||
throw new Error('Conflicting mappings for attribute ' + map1.attribute + ' and value ' + map1.value);
|
||||
}
|
||||
if (map1.replace) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
//
|
||||
// Matches a closing tag to a open tag
|
||||
//
|
||||
function matchClosing(input, tagname, html) {
|
||||
var closeTag = '</' + tagname + '>',
|
||||
openTag = new RegExp('< *' + tagname + '( *|>)', 'g'),
|
||||
closeCount = 0,
|
||||
openCount = -1,
|
||||
from, to, chunk
|
||||
;
|
||||
|
||||
from = html.search(input);
|
||||
to = from;
|
||||
|
||||
while(to > -1 && closeCount !== openCount) {
|
||||
to = html.indexOf(closeTag, to);
|
||||
if (to > -1) {
|
||||
to += tagname.length + 3;
|
||||
closeCount ++;
|
||||
chunk = html.slice(from, to);
|
||||
openCount = chunk.match(openTag).length;
|
||||
}
|
||||
}
|
||||
if (to === -1) {
|
||||
throw new Error('Unmatched tag ' + tagname + ' in ' + html)
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
var Merge = function Merge() {};
|
||||
Merge.prototype = {
|
||||
nest: [],
|
||||
|
||||
tag: new RegExp([
|
||||
'<',
|
||||
'(/?)', // 2 - is closing
|
||||
'([-:\\w]+)', // 3 - name
|
||||
'((?:[-\\w]+(?:', '=',
|
||||
'(?:\\w+|["|\'](?:.*)["|\']))?)*)', // 4 - attributes
|
||||
'(/?)', // 5 - is self-closing
|
||||
'>'
|
||||
].join('\\s*')),
|
||||
|
||||
//
|
||||
// HTML attribute parser.
|
||||
//
|
||||
attr: /([\-\w]*)\s*=\s*(?:(["\'])([\-\.\w\s\/:;&#]*)\2)/gi,
|
||||
|
||||
//
|
||||
// In HTML5 it's allowed to have to use self closing tags without closing
|
||||
// separators. So we need to detect these elements based on the tag name.
|
||||
//
|
||||
selfClosing: /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/,
|
||||
|
||||
//
|
||||
// ### function hasClass(str, className)
|
||||
// #### @str {String} the class attribute
|
||||
// #### @className {String} the className that the classAttribute should contain
|
||||
//
|
||||
// Helper function for detecting if a class attribute contains the className
|
||||
//
|
||||
hasClass: function hasClass(str, className) {
|
||||
return ~str.split(' ').indexOf(className);
|
||||
},
|
||||
|
||||
//
|
||||
// ### function iterate(html, value, components, tagname, key)
|
||||
// #### @html {String} peice of HTML
|
||||
// #### @value {Mixed} iterateable object with data
|
||||
// #### @components {Array} result of the this.tag regexp execution
|
||||
// #### @tagname {String} the name of the tag that we iterate on
|
||||
// #### @key {String} the key of the data that we need to extract from the value
|
||||
// #### @map {Object} attribute mappings
|
||||
//
|
||||
// Iterate over over the supplied HTML.
|
||||
//
|
||||
iterate: function iterate(html, value, components, tagname, key, map) {
|
||||
var output = '',
|
||||
segment = matchClosing(components.input, tagname, html),
|
||||
data = {};
|
||||
|
||||
// Is it an array?
|
||||
if (Array.isArray(value)) {
|
||||
// Yes: set the output to the result of iterating through the array
|
||||
for (var i = 0, l = value.length; i < l; i++) {
|
||||
// If there is a key, then we have a simple object and
|
||||
// must construct a simple object to use as the data
|
||||
if (key) {
|
||||
data[key] = value[i];
|
||||
} else {
|
||||
data = value[i];
|
||||
}
|
||||
|
||||
output += this.bind(segment, data, map);
|
||||
}
|
||||
|
||||
return output;
|
||||
} else if (typeof value === 'object') {
|
||||
// We need to refine the selection now that we know we're dealing with a
|
||||
// nested object
|
||||
segment = segment.slice(components.input.length, -(tagname.length + 3));
|
||||
return output += this.bind(segment, value, map);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function bind(html, data, map)
|
||||
// #### @html {String} the template that we need to modify
|
||||
// #### @data {Object} data for the template
|
||||
// #### @map {Mapper} instructions for the data placement in the template
|
||||
// Process the actual template
|
||||
//
|
||||
bind: function bind(html, data, map) {
|
||||
if (Array.isArray(data)) {
|
||||
var output = '';
|
||||
|
||||
for (var i = 0, l = data.length; i<l; i++) {
|
||||
output += this.bind(html, data[i], map);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
html = (html || '').toString();
|
||||
data = data || {};
|
||||
|
||||
var that = this;
|
||||
|
||||
var openers = 0,
|
||||
remove = 0,
|
||||
components,
|
||||
attributes,
|
||||
mappings = map && compileMappings(map.mappings),
|
||||
intag = false,
|
||||
tagname = '',
|
||||
isClosing = false,
|
||||
isSelfClosing = false,
|
||||
selfClosing = false,
|
||||
matchmode = false,
|
||||
createAttribute = map && map.conf && map.conf.create,
|
||||
closing,
|
||||
tagbody;
|
||||
|
||||
var c,
|
||||
buffer = '',
|
||||
left;
|
||||
|
||||
for (var i = 0, l = html.length; i < l; i++) {
|
||||
c = html.charAt(i);
|
||||
|
||||
//
|
||||
// Figure out which part of the HTML we are currently processing. And if
|
||||
// we have queued up enough HTML to process it's data.
|
||||
//
|
||||
if (c === '!' && intag && !matchmode) {
|
||||
intag = false;
|
||||
buffer += html.slice(left, i + 1);
|
||||
} else if (c === '<' && !intag) {
|
||||
closing = true;
|
||||
intag = true;
|
||||
left = i;
|
||||
} else if (c === '>' && intag) {
|
||||
intag = false;
|
||||
tagbody = html.slice(left, i + 1);
|
||||
components = this.tag.exec(tagbody);
|
||||
|
||||
if(!components) {
|
||||
intag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
isClosing = components[1];
|
||||
tagname = components[2];
|
||||
attributes = components[3];
|
||||
selfClosing = components[4];
|
||||
isSelfClosing = this.selfClosing.test(tagname);
|
||||
|
||||
if (matchmode) {
|
||||
//
|
||||
// and its a closing.
|
||||
//
|
||||
if (!!isClosing) {
|
||||
if (openers <= 0) {
|
||||
matchmode = false;
|
||||
} else {
|
||||
--openers;
|
||||
}
|
||||
} else if (!isSelfClosing) {
|
||||
//
|
||||
// and its not a self-closing tag
|
||||
//
|
||||
++openers;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isClosing && !matchmode) {
|
||||
//
|
||||
// if there is a match in progress and
|
||||
//
|
||||
if (mappings && mappings.length > 0) {
|
||||
for (var ii = mappings.length - 1; ii >= 0; ii--) {
|
||||
var setAttribute = false
|
||||
, mapping = mappings[ii]
|
||||
, shouldSetAttribute = mapping.re && attributes.match(mapping.re);
|
||||
|
||||
//
|
||||
// check if we are targetting a element only or attributes
|
||||
//
|
||||
if ('tag' in mapping && !this.attr.test(tagbody) && mapping.tag === tagname) {
|
||||
tagbody = tagbody + fetch(data, mapping, '', tagbody);
|
||||
continue;
|
||||
}
|
||||
|
||||
tagbody = tagbody.replace(this.attr, function(str, key, q, value, a) {
|
||||
var newdata;
|
||||
|
||||
if (shouldSetAttribute && mapping.replace !== key || remove) {
|
||||
return str;
|
||||
} else if (shouldSetAttribute || typeof mapping.replacePartial1 !== 'undefined') {
|
||||
setAttribute = true;
|
||||
|
||||
//
|
||||
// determine if we should use the replace argument or some value from the data object.
|
||||
//
|
||||
if (typeof mapping.replacePartial2 !== 'undefined') {
|
||||
newdata = value.replace(mapping.replacePartial1, mapping.replacePartial2);
|
||||
} else if (typeof mapping.replacePartial1 !== 'undefined' && mapping.dataKey) {
|
||||
newdata = value.replace(mapping.replacePartial1, fetch(data, mapping, value, tagbody, key));
|
||||
} else {
|
||||
newdata = fetch(data, mapping, value, tagbody, key);
|
||||
}
|
||||
|
||||
return key + '="' + (newdata || '') + '"';
|
||||
} else if (!mapping.replace && mapping.attribute === key) {
|
||||
if (
|
||||
mapping.value === value ||
|
||||
that.hasClass(value, mapping.value ||
|
||||
mappings.conf.where === key) ||
|
||||
(_toString.call(mapping.value) === '[object RegExp]' &&
|
||||
mapping.value.exec(value) !== null)
|
||||
) {
|
||||
if (mapping.remove) {
|
||||
//
|
||||
// only increase the remove counter if it's not a self
|
||||
// closing element. As matchmode is suffectient to
|
||||
// remove tose
|
||||
//
|
||||
if (!isSelfClosing) remove++;
|
||||
matchmode = true;
|
||||
} else if (mapping.plates) {
|
||||
var partial = that.bind(
|
||||
mapping.plates
|
||||
, typeof mapping.data === 'string' ? fetch(data, { dataKey: mapping.data }) : mapping.data || data
|
||||
, mapping.mapper
|
||||
);
|
||||
|
||||
buffer += tagbody + that.iterate(html, partial, components, tagname, undefined, map);
|
||||
matchmode = true;
|
||||
} else {
|
||||
var v = newdata = fetch(data, mapping, value, tagbody, key);
|
||||
newdata = tagbody + newdata;
|
||||
|
||||
if (Array.isArray(v)) {
|
||||
newdata = that.iterate(html, v, components, tagname, value, map);
|
||||
// If the item is an array, then we need to tell
|
||||
// Plates that we're dealing with nests
|
||||
that.nest.push(tagname);
|
||||
} else if (typeof v === 'object') {
|
||||
newdata = tagbody + that.iterate(html, v, components, tagname, value, map);
|
||||
}
|
||||
|
||||
buffer += newdata || '';
|
||||
matchmode = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
});
|
||||
|
||||
//
|
||||
// Do we need to create the attributes if they don't exist.
|
||||
//
|
||||
if (createAttribute && shouldSetAttribute && !setAttribute) {
|
||||
var spliced = selfClosing ? 2 : 1
|
||||
, close = selfClosing ? '/>': '>'
|
||||
, left = tagbody.substr(0, tagbody.length - spliced);
|
||||
|
||||
if (left[left.length - 1] === ' ') {
|
||||
left = left.substr(0, left.length - 1);
|
||||
|
||||
if (selfClosing) {
|
||||
close = ' ' + close;
|
||||
}
|
||||
}
|
||||
|
||||
tagbody = [
|
||||
left,
|
||||
' ',
|
||||
mapping.replace,
|
||||
'="',
|
||||
fetch(data, mapping),
|
||||
'"',
|
||||
close
|
||||
].join('');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// if there is no map, we are just looking to match
|
||||
// the specified id to a data key in the data object.
|
||||
//
|
||||
tagbody.replace(this.attr, function (attr, key, q, value, idx) {
|
||||
if (key === map && map.conf.where || 'id' && data[value]) {
|
||||
var v = data[value],
|
||||
nest = Array.isArray(v),
|
||||
output = nest || typeof v === 'object'
|
||||
? that.iterate(html.substr(left), v, components, tagname, value, map)
|
||||
: v;
|
||||
|
||||
// If the item is an array, then we need to tell
|
||||
// Plates that we're dealing with nests
|
||||
if (nest) { that.nest.push(tagname); }
|
||||
|
||||
buffer += nest ? output : tagbody + output;
|
||||
matchmode = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// if there is currently no match in progress
|
||||
// just write the tagbody to the buffer.
|
||||
//
|
||||
if (!matchmode && that.nest.length === 0) {
|
||||
if (!remove) buffer += tagbody;
|
||||
|
||||
if (remove && !!isClosing) --remove;
|
||||
} else if (!matchmode && that.nest.length) {
|
||||
this.nest.pop();
|
||||
}
|
||||
} else if (!intag && !matchmode) {
|
||||
//
|
||||
// currently not inside a tag and there is no
|
||||
// match in progress, we can write the char to
|
||||
// the buffer.
|
||||
//
|
||||
if (!remove) buffer += c;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// ### function Mapper(conf)
|
||||
// #### @conf {Object} configuration object
|
||||
// Constructor function for the Mapper instance that is responsible for
|
||||
// providing the mapping for the data structure
|
||||
//
|
||||
function Mapper(conf) {
|
||||
if (!(this instanceof Mapper)) { return new Mapper(conf); }
|
||||
|
||||
this.mappings = [];
|
||||
this.conf = conf || {};
|
||||
}
|
||||
|
||||
//
|
||||
// ### function last(newitem)
|
||||
// #### @newitem {Boolean} do we need to add a new item to the mapping
|
||||
// Helper function for adding new attribute maps to a Mapper instance
|
||||
//
|
||||
function last(newitem) {
|
||||
if (newitem) {
|
||||
this.mappings.push({});
|
||||
}
|
||||
|
||||
var m = this.mappings[this.mappings.length - 1];
|
||||
|
||||
if (m && m.attribute && m.value && m.dataKey && m.replace) {
|
||||
m.re = new RegExp(m.attribute + '=([\'"]?)' + m.value + '\\1');
|
||||
} else if (m) {
|
||||
delete m.re;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the actual chainable methods: where('class').is('foo').insert('bla')
|
||||
//
|
||||
Mapper.prototype = {
|
||||
//
|
||||
// ### function replace(val1, val2)
|
||||
// #### @val1 {String|RegExp} The part of the attribute that needs to be replaced
|
||||
// #### @val2 {String} The value it should be replaced with
|
||||
//
|
||||
replace: function replace(val1, val2) {
|
||||
var l = last.call(this);
|
||||
l.replacePartial1 = val1;
|
||||
l.replacePartial2 = val2;
|
||||
return this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function use(val)
|
||||
// #### @val {String} A string that represents a key.
|
||||
// Data will be inserted into the attribute that was specified in the
|
||||
// `where` clause.
|
||||
//
|
||||
use: function use(val) {
|
||||
last.call(this).dataKey = val;
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function where(val)
|
||||
// #### @val {String} an attribute that may be found in a tag
|
||||
// This method will initiate a clause. Once a clause has been established
|
||||
// other member methods will be chained to each other in any order.
|
||||
//
|
||||
where: function where(val) {
|
||||
last.call(this, true).attribute = val;
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function class(val)
|
||||
// #### @val {String} a value that may be found in the `class` attribute of a tag
|
||||
// the method name should be wrapped in quotes or it will throw errors in IE.
|
||||
//
|
||||
'class': function className(val) {
|
||||
return this.where('class').is(val);
|
||||
},
|
||||
|
||||
//
|
||||
// ### function tag(val)
|
||||
// #### @val {String} the name of the tag should be found
|
||||
//
|
||||
tag: function tag(val) {
|
||||
last.call(this, true).tag = val;
|
||||
return this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function is(val)
|
||||
// #### @val {string} The value of the attribute that was specified in the
|
||||
// `where` clause.
|
||||
//
|
||||
is: function is(val) {
|
||||
last.call(this).value = val;
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function has(val)
|
||||
// #### @val {String|RegExp} The value of the attribute that was specified
|
||||
// in the `where` clause.
|
||||
//
|
||||
has: function has(val) {
|
||||
last.call(this).value = val;
|
||||
this.replace(val);
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function insert(val)
|
||||
// #### @val {String} A string that represents a key. Data will be inserted
|
||||
// in to the attribute that was specified in the `where` clause.
|
||||
//
|
||||
insert: function insert(val) {
|
||||
var l = last.call(this);
|
||||
l.replace = l.attribute;
|
||||
l.dataKey = val;
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function as(val)
|
||||
// #### @val {String} A string that represents an attribute in the tag.
|
||||
// If there is no attribute by that name name found, one may be created
|
||||
// depending on the options that where passed in the `Plates.Map`
|
||||
// constructor.
|
||||
//
|
||||
as: function as(val) {
|
||||
last.call(this).replace = val;
|
||||
return last.call(this) && this;
|
||||
},
|
||||
|
||||
//
|
||||
// ### function remove()
|
||||
// This will remove the element that was specified in the `where` clause
|
||||
// from the template.
|
||||
//
|
||||
remove: function remove() {
|
||||
last.call(this).remove = true;
|
||||
return last.call(this, true);
|
||||
},
|
||||
|
||||
//
|
||||
// ### function append(plates, data, map)
|
||||
// #### @plates {String} Template or path/id of the template
|
||||
// #### @data {Object|String} data for the appended template
|
||||
// #### @map {Plates.Map} mapping for the data
|
||||
//
|
||||
append: function append(plates, data, map) {
|
||||
var l = last.call(this);
|
||||
|
||||
if (data instanceof Mapper) {
|
||||
map = data;
|
||||
data = undefined;
|
||||
}
|
||||
|
||||
// If the supplied plates template doesn't contain any HTML it's most
|
||||
// likely that we need to import it. To improve performance we will cache
|
||||
// the result of the file system.
|
||||
if (!/<[^<]+?>/.test(plates) && !exports.cache[plates]) {
|
||||
// figure out if we are running in Node.js or a browser
|
||||
if ('document' in env && 'getElementById' in env.document) {
|
||||
exports.cache[plates] = document.getElementById(plates).innerHTML;
|
||||
} else {
|
||||
exports.cache[plates] = require('fs').readFileSync(
|
||||
require('path').join(process.cwd(), plates),
|
||||
'utf8'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
l.plates = exports.cache[plates] || plates;
|
||||
l.data = data;
|
||||
l.mapper = map;
|
||||
|
||||
return last.call(this, true);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Provide helpful aliases that well help with increased compatibility as not
|
||||
// all browsers allow the Mapper#class prototype (IE).
|
||||
//
|
||||
Mapper.prototype.className = Mapper.prototype['class'];
|
||||
|
||||
//
|
||||
// Aliases of different methods.
|
||||
//
|
||||
Mapper.prototype.partial = Mapper.prototype.append;
|
||||
Mapper.prototype.to = Mapper.prototype.use;
|
||||
|
||||
//
|
||||
// Expose a simple cache object so people can clear the cached partials if
|
||||
// they want to.
|
||||
//
|
||||
exports.cache = {};
|
||||
|
||||
//
|
||||
// Expose the Plates#bind interface.
|
||||
//
|
||||
exports.bind = function bind(html, data, map) {
|
||||
var merge = new Merge();
|
||||
return merge.bind(html, data, map);
|
||||
};
|
||||
|
||||
//
|
||||
// Expose the Mapper.
|
||||
//
|
||||
exports.Map = Mapper;
|
||||
}(Plates, this);
|
|
@ -1,27 +0,0 @@
|
|||
package static
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/elazarl/go-bindata-assetfs"
|
||||
)
|
||||
|
||||
//go:generate go run ../contrib/generate-js.go -dir scripts/ -o scripts_gen/drone.min.js
|
||||
|
||||
//go:generate sassc --style compact styles/style.sass styles_gen/style.css
|
||||
//go:generate go-bindata-assetfs -ignore "\\.go" -pkg static -o static_gen.go ./...
|
||||
|
||||
func FileSystem() http.FileSystem {
|
||||
fs := &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: ""}
|
||||
return &binaryFileSystem{
|
||||
fs,
|
||||
}
|
||||
}
|
||||
|
||||
type binaryFileSystem struct {
|
||||
fs http.FileSystem
|
||||
}
|
||||
|
||||
func (b *binaryFileSystem) Open(name string) (http.File, error) {
|
||||
return b.fs.Open(name[1:])
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
.navbar
|
||||
background-color: #FFF;
|
||||
border-radius: 0px;
|
||||
height: 53px;
|
||||
z-index: 2;
|
||||
margin-top: 10px;
|
||||
|
||||
.navbar-brand
|
||||
background-image: url(/static/images/logo_dark.svg);
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-top: 3px;
|
||||
background-size: 30px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
|
||||
.navbar img
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
|
||||
.navbar .dropdown
|
||||
display: inline-block;
|
||||
|
||||
button
|
||||
background: none;
|
||||
border: none;
|
||||
color: #2b303b;
|
||||
min-wdith: 24px;
|
||||
max-width: 24px;
|
||||
|
||||
.material-icons
|
||||
line-height: 32px;
|
||||
min-wdith: 24px;
|
||||
max-width: 24px;
|
||||
|
||||
.navbar-nav.navbar-right
|
||||
display: inline-block;
|
||||
float: right;
|
||||
li
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
.navbar-form
|
||||
margin-right: 20px;
|
||||
width: 350px;
|
||||
.twitter-typeahead
|
||||
width: 100%;
|
||||
|
||||
.form-control
|
||||
color: #747C84;
|
||||
border: none;
|
||||
background-color: #eff1f5;
|
||||
border-radius: 0px;
|
||||
padding: 0.3rem 0.75rem;
|
||||
width: 100%;
|
|
@ -1,95 +0,0 @@
|
|||
input[type="range"]:focus ~ .slider-label
|
||||
display: inline-block;
|
||||
|
||||
input[type=range]
|
||||
-webkit-appearance: none;
|
||||
margin: 6px 0;
|
||||
width: 200px;
|
||||
|
||||
input[type=range]:focus
|
||||
outline: none;
|
||||
|
||||
input[type=range]::-webkit-slider-runnable-track
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
box-shadow: none;
|
||||
background: rgba(0, 150, 136, 0.5);
|
||||
background: rgba(102, 187, 106, 0.5);
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
|
||||
input[type=range]::-webkit-slider-thumb
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 50px;
|
||||
background: #009688;
|
||||
background: #66bb6a;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-top: -10px;
|
||||
|
||||
input[type=range]:focus::-webkit-slider-runnable-track
|
||||
background: rgba(0, 150, 136, 0.5);
|
||||
background: rgba(102, 187, 106, 0.5);
|
||||
|
||||
input[type=range]::-moz-range-track
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
box-shadow: none;
|
||||
background: rgba(0, 150, 136, 0.5);
|
||||
background: rgba(102, 187, 106, 0.5);
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
|
||||
input[type=range]::-moz-range-thumb
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
border-radius: 50px;
|
||||
background: #009688;
|
||||
background: #66bb6a;
|
||||
cursor: pointer;
|
||||
|
||||
input[type=range]::-ms-track
|
||||
width: 100%;
|
||||
height: 8.4px;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
border-width: 16px 0;
|
||||
color: transparent;
|
||||
|
||||
input[type=range]::-ms-fill-lower
|
||||
background: #2a6495;
|
||||
border: 0.2px solid #010101;
|
||||
border-radius: 2.6px;
|
||||
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
|
||||
|
||||
input[type=range]::-ms-fill-upper
|
||||
background: #3071a9;
|
||||
border: 0.2px solid #010101;
|
||||
border-radius: 2.6px;
|
||||
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
|
||||
|
||||
input[type=range]::-ms-thumb
|
||||
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
|
||||
border: 1px solid #000000;
|
||||
height: 36px;
|
||||
width: 16px;
|
||||
border-radius: 3px;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
|
||||
input[type=range]:focus::-ms-fill-lower
|
||||
background: #3071a9;
|
||||
|
||||
input[type=range]:focus::-ms-fill-upper
|
||||
background: #367ebd;
|
|
@ -1,46 +0,0 @@
|
|||
.success,
|
||||
.failure,
|
||||
.killed,
|
||||
.error,
|
||||
.running,
|
||||
.pending
|
||||
padding: 0px 15px;
|
||||
color: #FFF;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
|
||||
.error,
|
||||
.killed,
|
||||
.failure
|
||||
background: #bf616a;
|
||||
|
||||
.success
|
||||
background: #a3be8c;
|
||||
|
||||
.pending,
|
||||
.running
|
||||
background: #ebcb8b;
|
||||
animation: horizontal 2s ease infinite;
|
||||
|
||||
|
||||
@keyframes horizontal
|
||||
0%
|
||||
transform: translate(0,0)
|
||||
6%
|
||||
transform: translate(5px,0)
|
||||
12%
|
||||
transform: translate(0,0)
|
||||
18%
|
||||
transform: translate(5px,0)
|
||||
24%
|
||||
transform: translate(0,0)
|
||||
30%
|
||||
transform: translate(5px,0)
|
||||
36%,100%
|
||||
transform: translate(0,0)
|
|
@ -1,95 +0,0 @@
|
|||
.subnav
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid #EEE;
|
||||
height: 75px;
|
||||
min-height: 75px;
|
||||
max-height: 75px;
|
||||
margin-bottom: 40px;
|
||||
position: relative;
|
||||
|
||||
ol
|
||||
float: left;
|
||||
margin: 0px;
|
||||
margin-left: 20px;
|
||||
padding: 0px;
|
||||
|
||||
li
|
||||
line-height: 75px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 21px;
|
||||
|
||||
.btn
|
||||
background: transparent
|
||||
outline: none;
|
||||
.btn:focus
|
||||
outline: none;
|
||||
|
||||
.btn-info
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
border-color: #95AEC7;
|
||||
color: #95AEC7;
|
||||
|
||||
li.separator i
|
||||
vertical-align: middle
|
||||
|
||||
li a
|
||||
color: #2B303B;
|
||||
line-height: 75px;
|
||||
text-decoration: none;
|
||||
&:hover
|
||||
text-decoration: none;
|
||||
|
||||
|
||||
.nav-tabs
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
right: 30px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.nav-tabs .nav-link
|
||||
border: none;
|
||||
color: #C7CCD1;
|
||||
font-size: 13px;
|
||||
padding: 10px 20px;
|
||||
text-transform: uppercase;
|
||||
|
||||
.nav-tabs .nav-link.active
|
||||
border: 1px solid #eee;
|
||||
border-bottom: 1px solid #fff;
|
||||
color: #2b303b;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// .nav-tabs
|
||||
// position:absolute;
|
||||
// bottom:-1px;
|
||||
// right:30px;
|
||||
// border-bottom:1px solid #eee;
|
||||
//
|
||||
// .nav-tabs .nav-link
|
||||
// border:none;
|
||||
// color: #C7CCD1;
|
||||
// font-size:13px;
|
||||
// padding:10px 0px;
|
||||
// margin-left:10px;
|
||||
// margin-right:10px;
|
||||
// text-transform:uppercase;
|
||||
//
|
||||
// .nav-tabs .nav-item:last-child .nav-link
|
||||
// margin-right:5px;
|
||||
//
|
||||
// .nav-tabs .nav-link.active
|
||||
// border: none;
|
||||
// border-bottom:2px solid #2b303b;
|
||||
// color: #2b303b;
|
|
@ -1,43 +0,0 @@
|
|||
// http://codepen.io/batazor/pen/KwKryj
|
||||
|
||||
.switch
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 8px;
|
||||
border-radius: 10.416666666666668px;
|
||||
background: #E0E0E0;
|
||||
-webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
|
||||
.switch::before
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -8.604166666666667px;
|
||||
left: -2.604166666666667px;
|
||||
width: 26.04166666666667px;
|
||||
height: 26.04166666666667px;
|
||||
background: #bdbdbd;
|
||||
border-radius: 50%;
|
||||
-webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
switch:active::before
|
||||
box-shadow: 0 2px 10.416666666666668px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 0, 0, 0.1);
|
||||
|
||||
switch:active::before
|
||||
box-shadow: 0 2px 10.416666666666668px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 0, 0, 0.1);
|
||||
|
||||
input:checked + .switch
|
||||
background: rgba(0, 150, 136, 0.5);
|
||||
background: rgba(102, 187, 106, 0.5);
|
||||
|
||||
input:checked + .switch::before
|
||||
left: 20.562499999999996px;
|
||||
background: #009688;
|
||||
background: #66bb6a;
|
||||
|
||||
input:checked + .switch:active::before
|
||||
box-shadow: 0 2px 10.416666666666668px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 150, 136, 0.2);
|
|
@ -1,86 +0,0 @@
|
|||
.timeline
|
||||
padding-left: 50px;
|
||||
position: relative;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.card
|
||||
display: flex;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
border-top: 1px solid #eceeef;
|
||||
text-decoration: none;
|
||||
color: #2b303b;
|
||||
.card-header
|
||||
background: #FFF;
|
||||
border: none;
|
||||
padding: 0px;
|
||||
width: 50px;
|
||||
min-width: 50px;
|
||||
max-width: 50px;
|
||||
padding-top: 30px;
|
||||
.card-block
|
||||
flex: 1 1 auto;
|
||||
padding: 30px 12px 12px 12px;
|
||||
p
|
||||
color: #ADB3BA;
|
||||
margin-top: 2px;
|
||||
font-size: 0px;
|
||||
|
||||
em
|
||||
text-decoration: none;
|
||||
color: #747C84;
|
||||
font-style: normal;
|
||||
font-size: 0.9rem;
|
||||
span
|
||||
margin: 0px 5px;
|
||||
font-size: 0.9rem;
|
||||
|
||||
h3
|
||||
display: inline-block;
|
||||
line-height: 22px;
|
||||
font-size: 18px;
|
||||
|
||||
.card:nth-child(2)
|
||||
border-top: 0px;
|
||||
|
||||
.timeline:before
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 14px;
|
||||
z-index: -1;
|
||||
display: block;
|
||||
width: 1px;
|
||||
content: "";
|
||||
background-color: #DFE2E5;
|
||||
|
||||
.group
|
||||
padding-bottom: 16px;
|
||||
|
||||
.group-title
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
color: #ADB3BA;
|
||||
margin-bottom: 30px;
|
||||
margin-top: 30px;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
|
||||
.group-title:before
|
||||
content: '\f01f';
|
||||
font-family: "octicons";
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
font-size: 20px;
|
||||
background: #FFF;
|
||||
width: 24px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
color: #ADB3BA;
|
||||
|
||||
.group:first-child .group-title
|
||||
margin-top: 0px;
|
||||
|
||||
.group:last-child
|
||||
padding-bottom: 0px;
|
|
@ -1,195 +0,0 @@
|
|||
|
||||
// this is the build output section of the page that displays
|
||||
// the ansi terminal output.
|
||||
|
||||
#output
|
||||
background: #0d1926;
|
||||
color: #d9e6f2;
|
||||
margin-right: 15px;
|
||||
font-size: 13px;
|
||||
color: #eff1f5;
|
||||
border-radius: 2px;
|
||||
background: #2b303b;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
padding: 35px 40px;
|
||||
font-family: "Roboto Mono";
|
||||
min-height: calc(100vh - 205px);
|
||||
|
||||
#output > pre
|
||||
font-size: 13px;
|
||||
color: #eff1f5;
|
||||
border-radius: 2px;
|
||||
background: #2b303b;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
padding: 0px;
|
||||
font-family: "Roboto Mono";
|
||||
margin: 0px;
|
||||
margin-top: 25px;
|
||||
|
||||
#output > pre:first-child
|
||||
margin-top: 0px;
|
||||
|
||||
#output > pre:before
|
||||
content: attr(data-title);
|
||||
display: block;
|
||||
padding: 5px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.3);
|
||||
padding-left: 0px;
|
||||
|
||||
#follow
|
||||
position: absolute;
|
||||
|
||||
.build-summary
|
||||
padding-left: 20px;
|
||||
p
|
||||
color: #ADB3BA;
|
||||
margin-top: 4px;
|
||||
font-size: 0.9rem;
|
||||
em
|
||||
color: #747C84;
|
||||
text-decoration: none;
|
||||
font-style: normal;
|
||||
|
||||
// .success,
|
||||
// .failure,
|
||||
// .killed,
|
||||
// .error,
|
||||
// .running,
|
||||
// .pending
|
||||
// font-size: 15px;
|
||||
// padding: 2px 28px;
|
||||
// width: auto;
|
||||
.job-summary
|
||||
padding-left: 20px;
|
||||
font-size: 0.9rem;
|
||||
dt
|
||||
color: #ADB3BA;
|
||||
font-weight: normal;
|
||||
dd
|
||||
color: #747C84;
|
||||
text-decoration: none;
|
||||
font-style: normal;
|
||||
|
||||
.build-summary > div
|
||||
h3
|
||||
display: inline;
|
||||
line-height: 28px;
|
||||
font-size: 18px;
|
||||
a.material-icons
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
color: #ADB3BA;
|
||||
font-size: 20px;
|
||||
padding-left: 5px;
|
||||
|
||||
.job-list
|
||||
padding-left: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.job-list a
|
||||
h3
|
||||
margin-bottom: 10px;
|
||||
color: #2b303b;
|
||||
font-size: 14px;
|
||||
margin-top: 14px;
|
||||
.env
|
||||
font-family: "Roboto Mono"
|
||||
text-decoration: none;
|
||||
color: #747C84;
|
||||
font-size: 15px;
|
||||
display: block;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
position: relative;
|
||||
&:not(.active) > div:nth-child(2) > div
|
||||
display: none
|
||||
|
||||
// &:not(.active) > div:nth-child(2) > h3
|
||||
// color:#ADB3BA;
|
||||
// &:not(.active) > div:nth-child(1):after
|
||||
// content: "\2026";
|
||||
// display:block;
|
||||
// padding:0px 10px;
|
||||
// vertical-align:middle;
|
||||
// border:1px solid #eee;
|
||||
// background:#fff;
|
||||
// position:absolute;
|
||||
// right:0px;
|
||||
// top:0px;
|
||||
// height: 20px;
|
||||
// line-height: 10px;
|
||||
|
||||
.job-list a:last-child
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.job-list a > div:first-child
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
|
||||
//.job-list a.active:after
|
||||
// content: "";
|
||||
// border-left: 2px solid #eee;
|
||||
// position: absolute;
|
||||
// top: 0px;
|
||||
// left: -35px;
|
||||
// bottom: 0px;
|
||||
// width: 10px;
|
||||
|
||||
.build-btn-group
|
||||
margin-left: 20px;
|
||||
.btn
|
||||
background: #FFF;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-right: 10px;
|
||||
|
||||
.btn-danger
|
||||
border: 1px solid #bf616a;
|
||||
color: #bf616a;
|
||||
|
||||
&.btn-info
|
||||
border-color: #95AEC7;
|
||||
color: #95AEC7;
|
||||
|
||||
.tail
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 80px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
background: rgba(255,255,255,0.2);
|
||||
border-radius: 50%;
|
||||
box-shadow: 1px 2px 2px rgba(0,0,0,0.2);
|
||||
cursor: pointer;
|
||||
bottom: 15px;
|
||||
right: 60px;
|
||||
border: none;
|
||||
outline: none;
|
||||
display: none;
|
||||
|
||||
.tail i
|
||||
color: rgba(255,255,255,0.5);
|
||||
line-height: 38px;
|
||||
display: inline-block;
|
||||
|
||||
@supports (position:sticky)
|
||||
.sticky
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
|
||||
@supports not (position:sticky)
|
||||
.sticky
|
||||
top: 0px;
|
|
@ -1,331 +0,0 @@
|
|||
|
||||
.toc
|
||||
list-style-type: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding-bottom: 40px;
|
||||
|
||||
h2
|
||||
font-size: 21px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 20px;
|
||||
color: #2b303b;
|
||||
|
||||
ul
|
||||
list-style-type: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-bottom: 40px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-bottom: 40px;
|
||||
li
|
||||
a
|
||||
color: #2b303b;
|
||||
text-decoration: none;
|
||||
a:hover
|
||||
text-decoration: underline;
|
||||
|
||||
[data-method]:before
|
||||
content: attr(data-method);
|
||||
padding: 0px 10px;
|
||||
line-height: 18px;
|
||||
min-width: 70px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
border-radius: 2px;
|
||||
margin-right: 20px;
|
||||
|
||||
[data-method="GET"]:before
|
||||
background-color: #1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
background-color: #9B59B6;
|
||||
[data-method="POST"]:before
|
||||
background-color: #3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
background-color: #E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
background-color: #E74C3C;
|
||||
|
||||
|
||||
|
||||
[data-method]:before
|
||||
background: #FFF;
|
||||
border: 1px solid #FFF;
|
||||
[data-method="GET"]:before
|
||||
color: #1ABC9C;
|
||||
border-color: #1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
color: #9B59B6;
|
||||
border-color: #9B59B6;
|
||||
[data-method="POST"]:before
|
||||
color: #3498DB;
|
||||
border-color: #3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
color: #E67E22;
|
||||
border-color: #E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
color: #E74C3C;
|
||||
border-color: #E74C3C;
|
||||
|
||||
.operation
|
||||
|
||||
[data-method]:before
|
||||
content: attr(data-method);
|
||||
padding: 0px 10px;
|
||||
line-height: 18px;
|
||||
min-width: 70px;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
color: #FFF;
|
||||
border-radius: 2px;
|
||||
margin-right: 20px;
|
||||
background: #FFF;
|
||||
border: 1px solid #FFF;
|
||||
line-height: 20px;
|
||||
vertical-align: top;
|
||||
|
||||
|
||||
[data-method]:before
|
||||
background: #FFF;
|
||||
border: 1px solid #FFF;
|
||||
[data-method="GET"]:before
|
||||
color: #1ABC9C;
|
||||
border-color: #1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
color: #9B59B6;
|
||||
border-color: #9B59B6;
|
||||
[data-method="POST"]:before
|
||||
color: #3498DB;
|
||||
border-color: #3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
color: #E67E22;
|
||||
border-color: #E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
color: #E74C3C;
|
||||
border-color: #E74C3C;
|
||||
|
||||
.docs
|
||||
margin-top: 40px;
|
||||
padding: 0px 50px;
|
||||
padding-right: 40px;
|
||||
|
||||
.docs-api
|
||||
pre
|
||||
margin-right: 15px;
|
||||
font-size: 13px;
|
||||
color: #eff1f5;
|
||||
color: #2b303b;
|
||||
border-radius: 2px;
|
||||
background: #2b303b;
|
||||
background: #ECF0F1;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
padding: 25px 30px;
|
||||
font-family: "Roboto Mono";
|
||||
|
||||
margin-right: 0px;
|
||||
padding-left: 40px;
|
||||
background: #eff1f5;
|
||||
color: #2b303b;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
padding: 25px 30px;
|
||||
font-family: "Roboto Mono";
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
|
||||
.operation
|
||||
min-height: 100vh;
|
||||
padding: 20px 0px;
|
||||
display: flex
|
||||
&> aside,
|
||||
&> div
|
||||
min-width: 50%;
|
||||
max-width: 50%;
|
||||
width: 0%;
|
||||
padding-right: 40px;
|
||||
h2
|
||||
color: #2b303b;
|
||||
font-size: 21px;
|
||||
h3
|
||||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 40px;
|
||||
aside
|
||||
background: rgba(43, 48, 59, 0.95);
|
||||
box-sizing: border-box;
|
||||
padding: 20px 0px 10px 0px;
|
||||
border-radius: 2px;
|
||||
h4
|
||||
color: #d0d4d7;
|
||||
font-size: 15px;
|
||||
padding: 20px;
|
||||
padding-left: 40px;
|
||||
pre
|
||||
background: #2b303b;
|
||||
color: #d0d4d7;
|
||||
margin-right: 0px;
|
||||
padding-left: 40px;
|
||||
|
||||
.params
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style-type: none;
|
||||
border-top: 1px solid #f0f4f7
|
||||
li
|
||||
padding: 15px 10px;
|
||||
border-bottom: 1px solid #f0f4f7;
|
||||
font-size: 15px
|
||||
p
|
||||
line-height: 20px;
|
||||
margin: 0 0 0 170px;
|
||||
|
||||
li:after
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
|
||||
h4
|
||||
float: left;
|
||||
line-height: 20px;
|
||||
text-align: right;
|
||||
padding-right: 2 0px;
|
||||
width: 150px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
|
||||
small
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
color: #E67E22;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
|
||||
|
||||
.operation
|
||||
aside
|
||||
background: rgba(239, 241, 245, 0.49)
|
||||
h4
|
||||
color: #2b303b
|
||||
pre
|
||||
background: #eff1f5
|
||||
color: #2b303b
|
||||
|
||||
|
||||
|
||||
|
||||
.docs-usage
|
||||
.row
|
||||
display: flex;
|
||||
.content-nav
|
||||
max-width: 250px;
|
||||
min-width: 250px;
|
||||
width: 250px;
|
||||
ul
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style-type: none;
|
||||
li
|
||||
position: relative;
|
||||
color: rgba(0,0,0,0.5);
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
li a
|
||||
color: rgba(43, 48, 59, 0.8);
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
text-transform: none;
|
||||
li.active a
|
||||
color: #2b303b;
|
||||
font-size: 16px;
|
||||
text-transform: none;
|
||||
li.active:before
|
||||
content: "";
|
||||
border-left: 4px solid #2b303b;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: -20px;
|
||||
ul
|
||||
margin-bottom: 25px;
|
||||
margin-top: 5px;
|
||||
.content-main
|
||||
max-width: 900px;
|
||||
margin: 0px auto;
|
||||
margin-bottom: 40px;
|
||||
font-size: 14px;
|
||||
|
||||
p
|
||||
line-height: 20px;
|
||||
margin: 20px 0px;
|
||||
|
||||
blockquote
|
||||
color: #31708f;
|
||||
background-color: #d9edf7;
|
||||
border-color: #bcdff1;
|
||||
padding: 30px;
|
||||
margin: 15px 0px;
|
||||
border-radius: 2px;
|
||||
|
||||
blockquote p:first-child
|
||||
margin-top: 0px;
|
||||
|
||||
blockquote p:last-child
|
||||
margin-bottom: 0px;
|
||||
|
||||
strong
|
||||
font-weight: bold;
|
||||
|
||||
h1
|
||||
margin: 40px 0px 20px 0px;
|
||||
font-size: 22px;
|
||||
|
||||
h1:first-child
|
||||
margin-top: 0px;
|
||||
|
||||
h2
|
||||
margin: 40px 0px 30px 0px;
|
||||
font-size: 20px;
|
||||
border-top: 1px solid #EEE;
|
||||
padding-top: 30px;
|
||||
h3
|
||||
margin: 40px 0px 20px 0px;
|
||||
font-size: 16px;
|
||||
|
||||
ul code, ol code, p code
|
||||
background: #eff1f5;
|
||||
color: #2b303b;
|
||||
padding: 0px 7px;
|
||||
font-family: "Roboto Mono";
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
pre
|
||||
margin-right: 0px;
|
||||
padding-left: 40px;
|
||||
background: #eff1f5;
|
||||
color: #2b303b;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
padding: 25px 30px;
|
||||
font-family: "Roboto Mono";
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
pre > code
|
||||
background: #eff1f5;
|
||||
color: #2b303b;
|
||||
font-family: "Roboto Mono";
|
||||
font-size: 13px;
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
.repo-row
|
||||
.col-sm-4
|
||||
width: 100%;
|
||||
.col-sm-4:last-child .card
|
||||
border-bottom: none
|
||||
.card
|
||||
border: none;
|
||||
border-bottom: 1px solid #EEE;
|
||||
border-radius: 0px;
|
||||
position: relative
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
.card-block
|
||||
h3
|
||||
font-size: 1.1rem;
|
||||
color: #2b303b;
|
||||
.card-text
|
||||
color: rgba(0,0,0,0.5);
|
||||
font-size: 0.95rem;
|
||||
margin: 0px;
|
||||
|
||||
.btn-group
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 0px;
|
||||
|
||||
.btn-danger
|
||||
color: #bf616a;
|
||||
background: #FFF;
|
||||
border: 1px solid #bf616a;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
|
||||
.card-header
|
||||
background: #FFF;
|
||||
border-bottom: none;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
width: 45px;
|
||||
|
||||
.repo-search
|
||||
color: #747C84;
|
||||
border: none;
|
||||
background-color: #eff1f5;
|
||||
border-radius: 0px;
|
||||
padding: 9px 15px;
|
||||
width: 100%;
|
||||
margin-bottom: 45px;
|
||||
border-radius: 2px;
|
|
@ -1,120 +0,0 @@
|
|||
|
||||
body.login
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
div
|
||||
position: relative;
|
||||
width: 220px;
|
||||
height: 30px;
|
||||
|
||||
|
||||
|
||||
div.logo
|
||||
background-image: url(/static/images/logo_dark.svg);
|
||||
background-size: 35px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 30px;
|
||||
width: 35px;
|
||||
|
||||
animation-name: fadein;
|
||||
animation-duration: 1.5s;
|
||||
animation-timing-function: ease-in;
|
||||
|
||||
input[type="submit"],
|
||||
a
|
||||
background: #2b303b;
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
min-width: 150px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
animation-name: fadein;
|
||||
animation-duration: 1.5s;
|
||||
animation-timing-function: ease-in;
|
||||
|
||||
div.alert
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
line-height: 25px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
height: auto;
|
||||
border-radius: 0px;
|
||||
|
||||
body.login.login-form
|
||||
&> div
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
display: flex;
|
||||
div.logo
|
||||
width: 65px;
|
||||
position: relative;
|
||||
background-position: left center;
|
||||
animation-name: none;
|
||||
form
|
||||
flex: 1 1 auto;
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"]
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
background-color: #eff1f5;
|
||||
border: none;
|
||||
color: #747C84;
|
||||
|
||||
input[type="password"]
|
||||
margin-top: 1px;
|
||||
|
||||
input[type="submit"]
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
animation-name: none;
|
||||
|
||||
@keyframes flyin
|
||||
0%
|
||||
left: -3000px;
|
||||
100%
|
||||
left: 0px;
|
||||
|
||||
@keyframes flyin_right
|
||||
0%
|
||||
right: -3000px;
|
||||
100%
|
||||
right: 0px;
|
||||
|
||||
@keyframes fadein
|
||||
0%
|
||||
opacity: 0;
|
||||
100%
|
||||
opacity: 1;
|
|
@ -1,101 +0,0 @@
|
|||
|
||||
.container.repo_config,
|
||||
.container.repo_secrets
|
||||
max-width: 800px !important;
|
||||
.row
|
||||
border-bottom: 1px solid #f0f4f7;
|
||||
|
||||
.row:last-child
|
||||
border: none;
|
||||
margin-bottom: 30px;
|
||||
.col-md-12
|
||||
padding: 0px;
|
||||
.row:nth-last-child(2)
|
||||
border: none;
|
||||
|
||||
.col-md-3
|
||||
padding: 30px;
|
||||
padding-left: 0px;
|
||||
max-width: 200px;
|
||||
font-size: 15px;
|
||||
color: #2b303b;
|
||||
.col-md-9
|
||||
padding: 30px;
|
||||
color: #65737e;
|
||||
font-size: 15px;
|
||||
|
||||
.btn.btn-info
|
||||
border-color: #95AEC7;
|
||||
color: #95AEC7;
|
||||
background: #FFF;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
|
||||
pre
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
font-family: "Roboto Mono";
|
||||
color: #2b303b;
|
||||
|
||||
input[type="range"] + span
|
||||
margin-left: 15px;
|
||||
|
||||
.alert.alert-danger
|
||||
background: #FFF;
|
||||
border: 1px solid #bf616a;
|
||||
border-radius: 2px;
|
||||
margin-top: 40px;
|
||||
color: #bf616a;
|
||||
.btn.btn-danger
|
||||
margin-right: 15px;
|
||||
border: 1px solid #bf616a;
|
||||
color: #bf616a;
|
||||
background: #FFF;
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
|
||||
|
||||
.container.repo_secrets
|
||||
textarea
|
||||
border: none;
|
||||
background: #eff1f5;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 10px;
|
||||
height: 150px;
|
||||
padding: 10px 15px;
|
||||
.btn.btn-info
|
||||
margin-left: 0px;
|
||||
.result
|
||||
margin-top: 20px;
|
||||
white-space: pre;
|
||||
|
||||
|
||||
.container.repo_activate
|
||||
max-width: 800px !important;
|
||||
|
||||
.alert.alert-info
|
||||
color: #3498DB;
|
||||
background: rgba(52, 152, 219, 0.12);
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
margin-top: 20px;
|
||||
padding: 30px;
|
||||
.btn.btn-info
|
||||
color: #3498DB;
|
||||
background: #3498DB;
|
||||
border: 1px solid #3498DB;
|
||||
background: #FFF;
|
||||
border-radius: 2px;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
.container.profile
|
||||
max-width: 800px !important;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.row
|
||||
border-bottom: 1px solid #f0f4f7;
|
||||
|
||||
.row:last-child
|
||||
border-bottom: none;
|
||||
|
||||
.col-md-3
|
||||
padding: 30px;
|
||||
padding-left: 0px;
|
||||
max-width: 200px;
|
||||
font-size: 15px;
|
||||
color: #2b303b;
|
||||
|
||||
.col-md-9
|
||||
padding: 30px;
|
||||
color: #65737e;
|
||||
font-size: 15px;
|
||||
|
||||
.btn.btn-info
|
||||
border-color: #95AEC7;
|
||||
color: #95AEC7;
|
||||
background: #FFF;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
|
||||
pre
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
font-family: "Roboto Mono";
|
||||
color: #2b303b;
|
|
@ -1,71 +0,0 @@
|
|||
.user-row
|
||||
.col-sm-4
|
||||
width: 100%;
|
||||
.col-sm-4:last-child .card
|
||||
border-bottom: none
|
||||
.card
|
||||
border: none;
|
||||
border-bottom: 1px solid #EEE;
|
||||
border-radius: 0px;
|
||||
position: relative
|
||||
display: flex;
|
||||
.card-block
|
||||
h3
|
||||
font-size: 1.1rem;
|
||||
|
||||
.card-text
|
||||
color: rgba(0,0,0,0.5);
|
||||
font-size: 0.95rem;
|
||||
margin: 0px;
|
||||
|
||||
.btn-group
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 0px;
|
||||
|
||||
.btn
|
||||
background: #FFF;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
|
||||
.btn-danger
|
||||
border: 1px solid #bf616a;
|
||||
color: #bf616a;
|
||||
|
||||
.btn-info
|
||||
border-color: #95AEC7;
|
||||
color: #95AEC7;
|
||||
|
||||
.card-header
|
||||
background: #FFF;
|
||||
border-bottom: none;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
width: 45px;
|
||||
|
||||
|
||||
.card-header
|
||||
img
|
||||
vertical-align: middle;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 3px;
|
||||
|
||||
[data-admin="true"] h3:after
|
||||
content: "admin";
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
margin-left: 15px;
|
||||
background: #a3be8c;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
|
@ -1,56 +0,0 @@
|
|||
|
||||
|
||||
.tt-open
|
||||
position: absolute;
|
||||
top: 34px;
|
||||
left: 0px;
|
||||
z-index: 100;
|
||||
display: none;
|
||||
background: #FFF;
|
||||
min-width: 100%;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 0px;
|
||||
|
||||
.tt-selectable:hover,
|
||||
.tt-cursor
|
||||
background: #eff1f5;
|
||||
|
||||
.tt-selectable
|
||||
padding: 1rem 0.75rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
div:first-child
|
||||
width: 75px;
|
||||
max-width: 75px;
|
||||
min-width: 75px;
|
||||
|
||||
img
|
||||
width: 32px;
|
||||
max-width: 32px;
|
||||
min-width: 32px;
|
||||
border-radius: 50%;
|
||||
text-align: left;
|
||||
margin-left: 1rem;
|
||||
div:last-child
|
||||
flex: 1 1 auto;
|
||||
line-height: 32px;
|
||||
|
||||
.no-matches-message
|
||||
padding: 20px;
|
||||
color: rgba(0,0,0,0.5);
|
||||
font-style: italic;
|
||||
|
||||
.not-indexed-message
|
||||
padding: 20px;
|
||||
padding-bottom: 0px;
|
||||
color: rgba(0,0,0,0.5);
|
||||
font-style: italic;
|
||||
em
|
||||
color: #2b303b;
|
||||
p:last-child
|
||||
margin-top: 20px;
|
||||
font-size: 15px;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
a
|
||||
color: rgba(0, 0, 0, 0.8);
|
|
@ -1,108 +0,0 @@
|
|||
|
||||
|
||||
@import modules/badges.sass
|
||||
@import modules/navbar.sass
|
||||
@import modules/subnav.sass
|
||||
@import modules/switch.sass
|
||||
@import modules/range.sass
|
||||
@import modules/timeline.sass
|
||||
@import modules/status.sass
|
||||
|
||||
|
||||
@import pages/build.sass
|
||||
@import pages/users.sass
|
||||
@import pages/user.sass
|
||||
@import pages/repo.sass
|
||||
@import pages/login.sass
|
||||
@import pages/feed.sass
|
||||
@import pages/docs.sass
|
||||
|
||||
@import header
|
||||
@import search
|
||||
|
||||
|
||||
.hidden
|
||||
display: none;
|
||||
|
||||
// page navigation
|
||||
|
||||
:focus
|
||||
outline: none;
|
||||
|
||||
::-moz-focus-inner
|
||||
border: 0;
|
||||
|
||||
.container
|
||||
max-width: 980px !important;
|
||||
|
||||
|
||||
.modal-content
|
||||
padding: 20px;
|
||||
.form-control
|
||||
border-radius: 2px;
|
||||
.btn
|
||||
margin-top: 20px;
|
||||
|
||||
// node section
|
||||
|
||||
.node-row
|
||||
.col-sm-4
|
||||
width: 100%;
|
||||
.col-sm-4:last-child .card
|
||||
border-bottom: none
|
||||
.card
|
||||
border: none;
|
||||
border-bottom: 1px solid #EEE;
|
||||
border-radius: 0px;
|
||||
position: relative
|
||||
display: flex;
|
||||
.card-block
|
||||
h3
|
||||
font-size: 1.1rem;
|
||||
.card-text
|
||||
color: rgba(0,0,0,0.5);
|
||||
font-size: 0.95rem;
|
||||
margin: 0px;
|
||||
|
||||
.btn-group
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 0px;
|
||||
|
||||
.btn-danger
|
||||
color: #bf616a;
|
||||
background: #FFF;
|
||||
border: 1px solid #bf616a;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
width: auto;
|
||||
text-transform: uppercase;
|
||||
padding: 0px 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
height: auto;
|
||||
margin-left: 10px;
|
||||
|
||||
.card-header
|
||||
background: #FFF;
|
||||
border-bottom: none;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
width: 45px;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
i.linux_amd64
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: inline-block;
|
||||
background: url(/static/images/ubuntu.svg);
|
||||
background-size: 32px;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,492 +0,0 @@
|
|||
.navbar { background-color: #FFF; border-radius: 0px; height: 53px; z-index: 2; margin-top: 10px; }
|
||||
|
||||
.navbar-brand { background-image: url(/static/images/logo_dark.svg); width: 30px; height: 30px; margin-top: 3px; background-size: 30px; background-repeat: no-repeat; background-position: center center; }
|
||||
|
||||
.navbar img { width: 32px; height: 32px; border-radius: 50%; }
|
||||
|
||||
.navbar .dropdown { display: inline-block; }
|
||||
|
||||
.navbar .dropdown button { background: none; border: none; color: #2b303b; min-wdith: 24px; max-width: 24px; }
|
||||
|
||||
.navbar .dropdown button .material-icons { line-height: 32px; min-wdith: 24px; max-width: 24px; }
|
||||
|
||||
.navbar-nav.navbar-right { display: inline-block; float: right; }
|
||||
|
||||
.navbar-nav.navbar-right li { display: inline-block; vertical-align: middle; }
|
||||
|
||||
.navbar-form { margin-right: 20px; width: 350px; }
|
||||
|
||||
.navbar-form .twitter-typeahead { width: 100%; }
|
||||
|
||||
.navbar-form .form-control { color: #747C84; border: none; background-color: #eff1f5; border-radius: 0px; padding: 0.3rem 0.75rem; width: 100%; }
|
||||
|
||||
.subnav { background: #FFF; border-bottom: 1px solid #EEE; height: 75px; min-height: 75px; max-height: 75px; margin-bottom: 40px; position: relative; }
|
||||
|
||||
.subnav ol { float: left; margin: 0px; margin-left: 20px; padding: 0px; }
|
||||
|
||||
.subnav ol li { line-height: 75px; display: inline-block; vertical-align: middle; font-size: 21px; }
|
||||
|
||||
.subnav ol li .btn { background: transparent; outline: none; }
|
||||
|
||||
.subnav ol li .btn:focus { outline: none; }
|
||||
|
||||
.subnav ol li .btn-info { cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; border-color: #95AEC7; color: #95AEC7; }
|
||||
|
||||
.subnav ol li.separator i { vertical-align: middle; }
|
||||
|
||||
.subnav ol li a { color: #2B303B; line-height: 75px; text-decoration: none; }
|
||||
|
||||
.subnav ol li a:hover { text-decoration: none; }
|
||||
|
||||
.subnav .nav-tabs { position: absolute; bottom: -1px; right: 30px; border-bottom: 1px solid #eee; }
|
||||
|
||||
.subnav .nav-tabs .nav-link { border: none; color: #C7CCD1; font-size: 13px; padding: 10px 20px; text-transform: uppercase; }
|
||||
|
||||
.subnav .nav-tabs .nav-link.active { border: 1px solid #eee; border-bottom: 1px solid #fff; color: #2b303b; }
|
||||
|
||||
.switch { display: inline-block; position: relative; width: 40px; height: 8px; border-radius: 10.416666666666668px; background: #E0E0E0; -webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1); transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1); vertical-align: middle; cursor: pointer; }
|
||||
|
||||
.switch::before { content: ''; position: absolute; top: -8.604166666666667px; left: -2.604166666666667px; width: 26.04166666666667px; height: 26.04166666666667px; background: #bdbdbd; border-radius: 50%; -webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1); transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1); }
|
||||
|
||||
switch:active::before { box-shadow: 0 2px 10.41667px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 0, 0, 0.1); }
|
||||
|
||||
switch:active::before { box-shadow: 0 2px 10.41667px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 0, 0, 0.1); }
|
||||
|
||||
input:checked + .switch { background: rgba(0, 150, 136, 0.5); background: rgba(102, 187, 106, 0.5); }
|
||||
|
||||
input:checked + .switch::before { left: 20.562499999999996px; background: #009688; background: #66bb6a; }
|
||||
|
||||
input:checked + .switch:active::before { box-shadow: 0 2px 10.41667px rgba(0, 0, 0, 0.28), 0 0 0 25px rgba(0, 150, 136, 0.2); }
|
||||
|
||||
input[type="range"]:focus ~ .slider-label { display: inline-block; }
|
||||
|
||||
input[type=range] { -webkit-appearance: none; margin: 6px 0; width: 200px; }
|
||||
|
||||
input[type=range]:focus { outline: none; }
|
||||
|
||||
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 8px; cursor: pointer; animate: 0.2s; box-shadow: none; background: rgba(0, 150, 136, 0.5); background: rgba(102, 187, 106, 0.5); border-radius: 5px; border: none; }
|
||||
|
||||
input[type=range]::-webkit-slider-thumb { box-shadow: none; border: none; height: 26px; width: 26px; border-radius: 50px; background: #009688; background: #66bb6a; cursor: pointer; -webkit-appearance: none; margin-top: -10px; }
|
||||
|
||||
input[type=range]:focus::-webkit-slider-runnable-track { background: rgba(0, 150, 136, 0.5); background: rgba(102, 187, 106, 0.5); }
|
||||
|
||||
input[type=range]::-moz-range-track { width: 100%; height: 8px; cursor: pointer; animate: 0.2s; box-shadow: none; background: rgba(0, 150, 136, 0.5); background: rgba(102, 187, 106, 0.5); border-radius: 5px; border: none; }
|
||||
|
||||
input[type=range]::-moz-range-thumb { box-shadow: none; border: none; height: 26px; width: 26px; border-radius: 50px; background: #009688; background: #66bb6a; cursor: pointer; }
|
||||
|
||||
input[type=range]::-ms-track { width: 100%; height: 8.4px; cursor: pointer; animate: 0.2s; background: transparent; border-color: transparent; border-width: 16px 0; color: transparent; }
|
||||
|
||||
input[type=range]::-ms-fill-lower { background: #2a6495; border: 0.2px solid #010101; border-radius: 2.6px; box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; }
|
||||
|
||||
input[type=range]::-ms-fill-upper { background: #3071a9; border: 0.2px solid #010101; border-radius: 2.6px; box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; }
|
||||
|
||||
input[type=range]::-ms-thumb { box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; border: 1px solid #000000; height: 36px; width: 16px; border-radius: 3px; background: #ffffff; cursor: pointer; }
|
||||
|
||||
input[type=range]:focus::-ms-fill-lower { background: #3071a9; }
|
||||
|
||||
input[type=range]:focus::-ms-fill-upper { background: #367ebd; }
|
||||
|
||||
.timeline { padding-left: 50px; position: relative; margin-top: 10px; margin-bottom: 40px; }
|
||||
|
||||
.timeline .card { display: flex; border: none; border-radius: 0px; border-top: 1px solid #eceeef; text-decoration: none; color: #2b303b; }
|
||||
|
||||
.timeline .card .card-header { background: #FFF; border: none; padding: 0px; width: 50px; min-width: 50px; max-width: 50px; padding-top: 30px; }
|
||||
|
||||
.timeline .card .card-block { flex: 1 1 auto; padding: 30px 12px 12px 12px; }
|
||||
|
||||
.timeline .card .card-block p { color: #ADB3BA; margin-top: 2px; font-size: 0px; }
|
||||
|
||||
.timeline .card .card-block p em { text-decoration: none; color: #747C84; font-style: normal; font-size: 0.9rem; }
|
||||
|
||||
.timeline .card .card-block p span { margin: 0px 5px; font-size: 0.9rem; }
|
||||
|
||||
.timeline .card .card-block h3 { display: inline-block; line-height: 22px; font-size: 18px; }
|
||||
|
||||
.timeline .card:nth-child(2) { border-top: 0px; }
|
||||
|
||||
.timeline:before { position: absolute; top: 0; bottom: 0; left: 14px; z-index: -1; display: block; width: 1px; content: ""; background-color: #DFE2E5; }
|
||||
|
||||
.group { padding-bottom: 16px; }
|
||||
|
||||
.group-title { font-size: 13px; text-transform: uppercase; color: #ADB3BA; margin-bottom: 30px; margin-top: 30px; position: relative; line-height: 20px; }
|
||||
|
||||
.group-title:before { content: '\f01f'; font-family: "octicons"; position: absolute; left: -48px; font-size: 20px; background: #FFF; width: 24px; vertical-align: middle; text-align: center; color: #ADB3BA; }
|
||||
|
||||
.group:first-child .group-title { margin-top: 0px; }
|
||||
|
||||
.group:last-child { padding-bottom: 0px; }
|
||||
|
||||
.success, .failure, .killed, .error, .running, .pending { padding: 0px 15px; color: #FFF; width: 100px; text-align: center; border-radius: 2px; text-transform: uppercase; font-size: 11px; line-height: 22px; display: inline-block; margin-right: 10px; }
|
||||
|
||||
.error, .killed, .failure { background: #bf616a; }
|
||||
|
||||
.success { background: #a3be8c; }
|
||||
|
||||
.pending, .running { background: #ebcb8b; animation: horizontal 2s ease infinite; }
|
||||
|
||||
@keyframes horizontal { 0% { transform: translate(0, 0); }
|
||||
6% { transform: translate(5px, 0); }
|
||||
12% { transform: translate(0, 0); }
|
||||
18% { transform: translate(5px, 0); }
|
||||
24% { transform: translate(0, 0); }
|
||||
30% { transform: translate(5px, 0); }
|
||||
36%, 100% { transform: translate(0, 0); } }
|
||||
|
||||
#output { background: #0d1926; color: #d9e6f2; margin-right: 15px; font-size: 13px; color: #eff1f5; border-radius: 2px; background: #2b303b; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 35px 40px; font-family: "Roboto Mono"; min-height: calc(100vh - 205px); }
|
||||
|
||||
#output > pre { font-size: 13px; color: #eff1f5; border-radius: 2px; background: #2b303b; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 0px; font-family: "Roboto Mono"; margin: 0px; margin-top: 25px; }
|
||||
|
||||
#output > pre:first-child { margin-top: 0px; }
|
||||
|
||||
#output > pre:before { content: attr(data-title); display: block; padding: 5px; margin-bottom: 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.3); padding-left: 0px; }
|
||||
|
||||
#follow { position: absolute; }
|
||||
|
||||
.build-summary { padding-left: 20px; }
|
||||
|
||||
.build-summary p { color: #ADB3BA; margin-top: 4px; font-size: 0.9rem; }
|
||||
|
||||
.build-summary em { color: #747C84; text-decoration: none; font-style: normal; }
|
||||
|
||||
.job-summary { padding-left: 20px; font-size: 0.9rem; }
|
||||
|
||||
.job-summary dt { color: #ADB3BA; font-weight: normal; }
|
||||
|
||||
.job-summary dd { color: #747C84; text-decoration: none; font-style: normal; }
|
||||
|
||||
.build-summary > div h3 { display: inline; line-height: 28px; font-size: 18px; }
|
||||
|
||||
.build-summary > div h3 a.material-icons { vertical-align: middle; text-decoration: none; color: #ADB3BA; font-size: 20px; padding-left: 5px; }
|
||||
|
||||
.job-list { padding-left: 20px; margin-bottom: 20px; }
|
||||
|
||||
.job-list a { text-decoration: none; color: #747C84; font-size: 15px; display: block; border-top: 1px solid #eee; padding-top: 20px; padding-bottom: 20px; position: relative; }
|
||||
|
||||
.job-list a h3 { margin-bottom: 10px; color: #2b303b; font-size: 14px; margin-top: 14px; }
|
||||
|
||||
.job-list a h3 .env { font-family: "Roboto Mono"; }
|
||||
|
||||
.job-list a:not(.active) > div:nth-child(2) > div { display: none; }
|
||||
|
||||
.job-list a:last-child { border-bottom: 1px solid #eee; }
|
||||
|
||||
.job-list a > div:first-child { margin-bottom: 10px; position: relative; }
|
||||
|
||||
.build-btn-group { margin-left: 20px; }
|
||||
|
||||
.build-btn-group .btn { background: #FFF; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-right: 10px; }
|
||||
|
||||
.build-btn-group .btn .btn-danger { border: 1px solid #bf616a; color: #bf616a; }
|
||||
|
||||
.build-btn-group .btn.btn-info { border-color: #95AEC7; color: #95AEC7; }
|
||||
|
||||
.tail { position: fixed; bottom: 50px; right: 80px; width: 38px; height: 38px; background: rgba(255, 255, 255, 0.2); border-radius: 50%; box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.2); cursor: pointer; bottom: 15px; right: 60px; border: none; outline: none; display: none; }
|
||||
|
||||
.tail i { color: rgba(255, 255, 255, 0.5); line-height: 38px; display: inline-block; }
|
||||
|
||||
@supports (position: sticky) { .sticky { position: sticky; top: 20px; } }
|
||||
|
||||
@supports not (position: sticky) { .sticky { top: 0px; } }
|
||||
|
||||
.user-row .col-sm-4 { width: 100%; }
|
||||
|
||||
.user-row .col-sm-4:last-child .card { border-bottom: none; }
|
||||
|
||||
.user-row .card { border: none; border-bottom: 1px solid #EEE; border-radius: 0px; position: relative; display: flex; }
|
||||
|
||||
.user-row .card-block h3 { font-size: 1.1rem; }
|
||||
|
||||
.user-row .card-block .card-text { color: rgba(0, 0, 0, 0.5); font-size: 0.95rem; margin: 0px; }
|
||||
|
||||
.user-row .card-block .btn-group { position: absolute; top: 15px; right: 0px; }
|
||||
|
||||
.user-row .card-block .btn-group .btn { background: #FFF; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; }
|
||||
|
||||
.user-row .card-block .btn-group .btn-danger { border: 1px solid #bf616a; color: #bf616a; }
|
||||
|
||||
.user-row .card-block .btn-group .btn-info { border-color: #95AEC7; color: #95AEC7; }
|
||||
|
||||
.user-row .card-header { background: #FFF; border-bottom: none; padding-right: 0px; padding-left: 0px; width: 45px; }
|
||||
|
||||
.card-header img { vertical-align: middle; width: 32px; height: 32px; border-radius: 3px; }
|
||||
|
||||
[data-admin="true"] h3:after { content: "admin"; text-transform: uppercase; color: #fff; display: inline-block; font-size: 12px; margin-left: 15px; background: #a3be8c; border-radius: 3px; padding: 2px 5px; }
|
||||
|
||||
.container.profile { max-width: 800px !important; margin-bottom: 40px; }
|
||||
|
||||
.container.profile .row { border-bottom: 1px solid #f0f4f7; }
|
||||
|
||||
.container.profile .row:last-child { border-bottom: none; }
|
||||
|
||||
.container.profile .col-md-3 { padding: 30px; padding-left: 0px; max-width: 200px; font-size: 15px; color: #2b303b; }
|
||||
|
||||
.container.profile .col-md-9 { padding: 30px; color: #65737e; font-size: 15px; }
|
||||
|
||||
.container.profile .btn.btn-info { border-color: #95AEC7; color: #95AEC7; background: #FFF; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; }
|
||||
|
||||
.container.profile pre { white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-family: "Roboto Mono"; color: #2b303b; }
|
||||
|
||||
.container.repo_config, .container.repo_secrets { max-width: 800px !important; }
|
||||
|
||||
.container.repo_config .row, .container.repo_secrets .row { border-bottom: 1px solid #f0f4f7; }
|
||||
|
||||
.container.repo_config .row:last-child, .container.repo_secrets .row:last-child { border: none; margin-bottom: 30px; }
|
||||
|
||||
.container.repo_config .row:last-child .col-md-12, .container.repo_secrets .row:last-child .col-md-12 { padding: 0px; }
|
||||
|
||||
.container.repo_config .row:nth-last-child(2), .container.repo_secrets .row:nth-last-child(2) { border: none; }
|
||||
|
||||
.container.repo_config .col-md-3, .container.repo_secrets .col-md-3 { padding: 30px; padding-left: 0px; max-width: 200px; font-size: 15px; color: #2b303b; }
|
||||
|
||||
.container.repo_config .col-md-9, .container.repo_secrets .col-md-9 { padding: 30px; color: #65737e; font-size: 15px; }
|
||||
|
||||
.container.repo_config .btn.btn-info, .container.repo_secrets .btn.btn-info { border-color: #95AEC7; color: #95AEC7; background: #FFF; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; }
|
||||
|
||||
.container.repo_config pre, .container.repo_secrets pre { white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-family: "Roboto Mono"; color: #2b303b; }
|
||||
|
||||
.container.repo_config input[type="range"] + span, .container.repo_secrets input[type="range"] + span { margin-left: 15px; }
|
||||
|
||||
.container.repo_config .alert.alert-danger, .container.repo_secrets .alert.alert-danger { background: #FFF; border: 1px solid #bf616a; border-radius: 2px; margin-top: 40px; color: #bf616a; }
|
||||
|
||||
.container.repo_config .alert.alert-danger .btn.btn-danger, .container.repo_secrets .alert.alert-danger .btn.btn-danger { margin-right: 15px; border: 1px solid #bf616a; color: #bf616a; background: #FFF; border-radius: 2px; font-size: 13px; text-transform: uppercase; }
|
||||
|
||||
.container.repo_secrets textarea { border: none; background: #eff1f5; width: 100%; border-radius: 3px; margin-bottom: 10px; height: 150px; padding: 10px 15px; }
|
||||
|
||||
.container.repo_secrets .btn.btn-info { margin-left: 0px; }
|
||||
|
||||
.container.repo_secrets .result { margin-top: 20px; white-space: pre; }
|
||||
|
||||
.container.repo_activate { max-width: 800px !important; }
|
||||
|
||||
.container.repo_activate .alert.alert-info { color: #3498DB; background: rgba(52, 152, 219, 0.12); border-radius: 2px; border: none; margin-top: 20px; padding: 30px; }
|
||||
|
||||
.container.repo_activate .btn.btn-info { color: #3498DB; background: #3498DB; border: 1px solid #3498DB; background: #FFF; border-radius: 2px; text-transform: uppercase; font-size: 13px; }
|
||||
|
||||
body.login { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; width: 100%; height: 100%; overflow: hidden; }
|
||||
|
||||
body.login div { position: relative; width: 220px; height: 30px; }
|
||||
|
||||
body.login div div.logo { background-image: url(/static/images/logo_dark.svg); background-size: 35px; background-repeat: no-repeat; background-position: center center; position: absolute; top: 0px; left: 0px; height: 30px; width: 35px; animation-name: fadein; animation-duration: 1.5s; animation-timing-function: ease-in; }
|
||||
|
||||
body.login div input[type="submit"], body.login div a { background: #2b303b; color: #FFF; text-decoration: none; position: absolute; top: 0px; right: 0px; text-transform: uppercase; font-size: 13px; min-width: 150px; text-align: center; padding: 5px; border: none; animation-name: fadein; animation-duration: 1.5s; animation-timing-function: ease-in; }
|
||||
|
||||
body.login div.alert { position: fixed; top: 0px; left: 0px; right: 0px; line-height: 25px; padding: 20px; width: 100%; border: none; text-align: center; vertical-align: middle; height: auto; border-radius: 0px; }
|
||||
|
||||
body.login.login-form > div { width: 300px; height: 100px; display: flex; }
|
||||
|
||||
body.login.login-form > div div.logo { width: 65px; position: relative; background-position: left center; animation-name: none; }
|
||||
|
||||
body.login.login-form > div form { flex: 1 1 auto; }
|
||||
|
||||
body.login.login-form > div input[type="text"], body.login.login-form > div input[type="password"] { display: block; width: 100%; padding: 5px 10px; background-color: #eff1f5; border: none; color: #747C84; }
|
||||
|
||||
body.login.login-form > div input[type="password"] { margin-top: 1px; }
|
||||
|
||||
body.login.login-form > div input[type="submit"] { position: relative; width: 100%; margin-top: 20px; animation-name: none; }
|
||||
|
||||
@keyframes flyin { 0% { left: -3000px; }
|
||||
100% { left: 0px; } }
|
||||
|
||||
@keyframes flyin_right { 0% { right: -3000px; }
|
||||
100% { right: 0px; } }
|
||||
|
||||
@keyframes fadein { 0% { opacity: 0; }
|
||||
100% { opacity: 1; } }
|
||||
|
||||
.repo-row .col-sm-4 { width: 100%; }
|
||||
|
||||
.repo-row .col-sm-4:last-child .card { border-bottom: none; }
|
||||
|
||||
.repo-row .card { border: none; border-bottom: 1px solid #EEE; border-radius: 0px; position: relative; display: flex; text-decoration: none; }
|
||||
|
||||
.repo-row .card-block h3 { font-size: 1.1rem; color: #2b303b; }
|
||||
|
||||
.repo-row .card-block .card-text { color: rgba(0, 0, 0, 0.5); font-size: 0.95rem; margin: 0px; }
|
||||
|
||||
.repo-row .card-block .btn-group { position: absolute; top: 15px; right: 0px; }
|
||||
|
||||
.repo-row .card-block .btn-group .btn-danger { color: #bf616a; background: #FFF; border: 1px solid #bf616a; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; }
|
||||
|
||||
.repo-row .card-header { background: #FFF; border-bottom: none; padding-right: 0px; padding-left: 0px; width: 45px; }
|
||||
|
||||
.repo-search { color: #747C84; border: none; background-color: #eff1f5; border-radius: 0px; padding: 9px 15px; width: 100%; margin-bottom: 45px; border-radius: 2px; }
|
||||
|
||||
.toc { list-style-type: none; padding: 0px; margin: 0px; padding-bottom: 40px; }
|
||||
|
||||
.toc h2 { font-size: 21px; font-weight: normal; margin-bottom: 20px; color: #2b303b; }
|
||||
|
||||
.toc ul { list-style-type: none; padding: 0px; margin: 0px; margin-bottom: 40px; border-bottom: 1px solid #EEE; padding-bottom: 40px; }
|
||||
|
||||
.toc ul li a { color: #2b303b; text-decoration: none; }
|
||||
|
||||
.toc ul li a:hover { text-decoration: underline; }
|
||||
|
||||
.toc [data-method]:before { content: attr(data-method); padding: 0px 10px; line-height: 18px; min-width: 70px; font-size: 11px; text-transform: uppercase; display: inline-block; text-align: center; color: #FFF; border-radius: 2px; margin-right: 20px; }
|
||||
|
||||
.toc [data-method="GET"]:before { background-color: #1ABC9C; }
|
||||
|
||||
.toc [data-method="PUT"]:before { background-color: #9B59B6; }
|
||||
|
||||
.toc [data-method="POST"]:before { background-color: #3498DB; }
|
||||
|
||||
.toc [data-method="PATCH"]:before { background-color: #E67E22; }
|
||||
|
||||
.toc [data-method="DELETE"]:before { background-color: #E74C3C; }
|
||||
|
||||
.toc [data-method]:before { background: #FFF; border: 1px solid #FFF; }
|
||||
|
||||
.toc [data-method="GET"]:before { color: #1ABC9C; border-color: #1ABC9C; }
|
||||
|
||||
.toc [data-method="PUT"]:before { color: #9B59B6; border-color: #9B59B6; }
|
||||
|
||||
.toc [data-method="POST"]:before { color: #3498DB; border-color: #3498DB; }
|
||||
|
||||
.toc [data-method="PATCH"]:before { color: #E67E22; border-color: #E67E22; }
|
||||
|
||||
.toc [data-method="DELETE"]:before { color: #E74C3C; border-color: #E74C3C; }
|
||||
|
||||
.operation [data-method]:before { content: attr(data-method); padding: 0px 10px; line-height: 18px; min-width: 70px; font-size: 11px; text-transform: uppercase; display: inline-block; text-align: center; color: #FFF; border-radius: 2px; margin-right: 20px; background: #FFF; border: 1px solid #FFF; line-height: 20px; vertical-align: top; }
|
||||
|
||||
.operation [data-method]:before { background: #FFF; border: 1px solid #FFF; }
|
||||
|
||||
.operation [data-method="GET"]:before { color: #1ABC9C; border-color: #1ABC9C; }
|
||||
|
||||
.operation [data-method="PUT"]:before { color: #9B59B6; border-color: #9B59B6; }
|
||||
|
||||
.operation [data-method="POST"]:before { color: #3498DB; border-color: #3498DB; }
|
||||
|
||||
.operation [data-method="PATCH"]:before { color: #E67E22; border-color: #E67E22; }
|
||||
|
||||
.operation [data-method="DELETE"]:before { color: #E74C3C; border-color: #E74C3C; }
|
||||
|
||||
.docs { margin-top: 40px; padding: 0px 50px; padding-right: 40px; }
|
||||
|
||||
.docs-api pre { margin-right: 15px; font-size: 13px; color: #eff1f5; color: #2b303b; border-radius: 2px; background: #2b303b; background: #ECF0F1; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 25px 30px; font-family: "Roboto Mono"; margin-right: 0px; padding-left: 40px; background: #eff1f5; color: #2b303b; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 25px 30px; font-family: "Roboto Mono"; border-radius: 2px; font-size: 13px; }
|
||||
|
||||
.operation { min-height: 100vh; padding: 20px 0px; display: flex; }
|
||||
|
||||
.operation > aside, .operation > div { min-width: 50%; max-width: 50%; width: 0%; padding-right: 40px; }
|
||||
|
||||
.operation h2 { color: #2b303b; font-size: 21px; }
|
||||
|
||||
.operation h3 { font-size: 16px; margin-bottom: 20px; margin-top: 40px; }
|
||||
|
||||
.operation aside { background: rgba(43, 48, 59, 0.95); box-sizing: border-box; padding: 20px 0px 10px 0px; border-radius: 2px; }
|
||||
|
||||
.operation aside h4 { color: #d0d4d7; font-size: 15px; padding: 20px; padding-left: 40px; }
|
||||
|
||||
.operation aside pre { background: #2b303b; color: #d0d4d7; margin-right: 0px; padding-left: 40px; }
|
||||
|
||||
.operation .params { padding: 0px; margin: 0px; list-style-type: none; border-top: 1px solid #f0f4f7; }
|
||||
|
||||
.operation .params li { padding: 15px 10px; border-bottom: 1px solid #f0f4f7; font-size: 15px; }
|
||||
|
||||
.operation .params li p { line-height: 20px; margin: 0 0 0 170px; }
|
||||
|
||||
.operation .params li:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }
|
||||
|
||||
.operation .params h4 { float: left; line-height: 20px; text-align: right; padding-right: 2 0px; width: 150px; font-weight: bold; font-size: 15px; }
|
||||
|
||||
.operation .params small { display: block; text-transform: uppercase; color: #E67E22; font-size: 11px; font-weight: normal; margin-top: 5px; }
|
||||
|
||||
.operation aside { background: rgba(239, 241, 245, 0.49); }
|
||||
|
||||
.operation aside h4 { color: #2b303b; }
|
||||
|
||||
.operation aside pre { background: #eff1f5; color: #2b303b; }
|
||||
|
||||
.docs-usage .row { display: flex; }
|
||||
|
||||
.docs-usage .row .content-nav { max-width: 250px; min-width: 250px; width: 250px; }
|
||||
|
||||
.docs-usage .row .content-nav ul { padding: 0px; margin: 0px; list-style-type: none; }
|
||||
|
||||
.docs-usage .row .content-nav ul li { position: relative; color: rgba(0, 0, 0, 0.5); text-transform: uppercase; font-size: 13px; }
|
||||
|
||||
.docs-usage .row .content-nav ul li a { color: rgba(43, 48, 59, 0.8); line-height: 30px; display: block; font-size: 16px; text-transform: none; }
|
||||
|
||||
.docs-usage .row .content-nav ul li.active a { color: #2b303b; font-size: 16px; text-transform: none; }
|
||||
|
||||
.docs-usage .row .content-nav ul li.active:before { content: ""; border-left: 4px solid #2b303b; position: absolute; top: 0px; bottom: 0px; left: -20px; }
|
||||
|
||||
.docs-usage .row .content-nav ul ul { margin-bottom: 25px; margin-top: 5px; }
|
||||
|
||||
.docs-usage .row .content-main { max-width: 900px; margin: 0px auto; margin-bottom: 40px; font-size: 14px; }
|
||||
|
||||
.docs-usage .row .content-main p { line-height: 20px; margin: 20px 0px; }
|
||||
|
||||
.docs-usage .row .content-main blockquote { color: #31708f; background-color: #d9edf7; border-color: #bcdff1; padding: 30px; margin: 15px 0px; border-radius: 2px; }
|
||||
|
||||
.docs-usage .row .content-main blockquote p:first-child { margin-top: 0px; }
|
||||
|
||||
.docs-usage .row .content-main blockquote p:last-child { margin-bottom: 0px; }
|
||||
|
||||
.docs-usage .row .content-main strong { font-weight: bold; }
|
||||
|
||||
.docs-usage .row .content-main h1 { margin: 40px 0px 20px 0px; font-size: 22px; }
|
||||
|
||||
.docs-usage .row .content-main h1:first-child { margin-top: 0px; }
|
||||
|
||||
.docs-usage .row .content-main h2 { margin: 40px 0px 30px 0px; font-size: 20px; border-top: 1px solid #EEE; padding-top: 30px; }
|
||||
|
||||
.docs-usage .row .content-main h3 { margin: 40px 0px 20px 0px; font-size: 16px; }
|
||||
|
||||
.docs-usage .row .content-main ul code, .docs-usage .row .content-main ol code, .docs-usage .row .content-main p code { background: #eff1f5; color: #2b303b; padding: 0px 7px; font-family: "Roboto Mono"; font-size: 13px; white-space: nowrap; }
|
||||
|
||||
.docs-usage .row .content-main pre { margin-right: 0px; padding-left: 40px; background: #eff1f5; color: #2b303b; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 25px 30px; font-family: "Roboto Mono"; border-radius: 2px; font-size: 13px; }
|
||||
|
||||
.docs-usage .row .content-main pre > code { background: #eff1f5; color: #2b303b; font-family: "Roboto Mono"; font-size: 13px; }
|
||||
|
||||
.tt-open { position: absolute; top: 34px; left: 0px; z-index: 100; display: none; background: #FFF; min-width: 100%; border: 1px solid #eee; border-radius: 0px; }
|
||||
|
||||
.tt-selectable:hover, .tt-cursor { background: #eff1f5; }
|
||||
|
||||
.tt-selectable { padding: 1rem 0.75rem; cursor: pointer; display: flex; }
|
||||
|
||||
.tt-selectable div:first-child { width: 75px; max-width: 75px; min-width: 75px; }
|
||||
|
||||
.tt-selectable div:first-child img { width: 32px; max-width: 32px; min-width: 32px; border-radius: 50%; text-align: left; margin-left: 1rem; }
|
||||
|
||||
.tt-selectable div:last-child { flex: 1 1 auto; line-height: 32px; }
|
||||
|
||||
.no-matches-message { padding: 20px; color: rgba(0, 0, 0, 0.5); font-style: italic; }
|
||||
|
||||
.not-indexed-message { padding: 20px; padding-bottom: 0px; color: rgba(0, 0, 0, 0.5); font-style: italic; }
|
||||
|
||||
.not-indexed-message em { color: #2b303b; }
|
||||
|
||||
.not-indexed-message p:last-child { margin-top: 20px; font-size: 15px; color: rgba(0, 0, 0, 0.4); }
|
||||
|
||||
.not-indexed-message p:last-child a { color: rgba(0, 0, 0, 0.8); }
|
||||
|
||||
.hidden { display: none; }
|
||||
|
||||
:focus { outline: none; }
|
||||
|
||||
::-moz-focus-inner { border: 0; }
|
||||
|
||||
.container { max-width: 980px !important; }
|
||||
|
||||
.modal-content { padding: 20px; }
|
||||
|
||||
.modal-content .form-control { border-radius: 2px; }
|
||||
|
||||
.modal-content .btn { margin-top: 20px; }
|
||||
|
||||
.node-row .col-sm-4 { width: 100%; }
|
||||
|
||||
.node-row .col-sm-4:last-child .card { border-bottom: none; }
|
||||
|
||||
.node-row .card { border: none; border-bottom: 1px solid #EEE; border-radius: 0px; position: relative; display: flex; }
|
||||
|
||||
.node-row .card-block h3 { font-size: 1.1rem; }
|
||||
|
||||
.node-row .card-block .card-text { color: rgba(0, 0, 0, 0.5); font-size: 0.95rem; margin: 0px; }
|
||||
|
||||
.node-row .card-block .btn-group { position: absolute; top: 15px; right: 0px; }
|
||||
|
||||
.node-row .card-block .btn-group .btn-danger { color: #bf616a; background: #FFF; border: 1px solid #bf616a; outline: none; cursor: pointer; width: auto; text-transform: uppercase; padding: 0px 10px; border-radius: 2px; font-size: 11px; line-height: 30px; height: auto; margin-left: 10px; }
|
||||
|
||||
.node-row .card-header { background: #FFF; border-bottom: none; padding-right: 0px; padding-left: 0px; width: 45px; }
|
||||
|
||||
i.linux_amd64 { width: 32px; height: 32px; display: inline-block; background: url(/static/images/ubuntu.svg); background-size: 32px; background-repeat: no-repeat; }
|
|
@ -24,6 +24,7 @@ func (db *datastore) GetRepoListOf(listof []*model.RepoLite) ([]*model.Repo, err
|
|||
repos []*model.Repo
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
|
@ -31,7 +32,9 @@ func (db *datastore) GetRepoListOf(listof []*model.RepoLite) ([]*model.Repo, err
|
|||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
err := meddler.QueryAll(db, &repos, fmt.Sprintf(repoListOfQuery, stmt), args...)
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &repos, fmt.Sprintf(repoListOfQuery, stmt), args...)
|
||||
}
|
||||
return repos, err
|
||||
}
|
||||
|
||||
|
|
|
@ -27,9 +27,11 @@ func (db *datastore) GetUserList() ([]*model.User, error) {
|
|||
|
||||
func (db *datastore) GetUserFeed(listof []*model.RepoLite) ([]*model.Feed, error) {
|
||||
var (
|
||||
feed []*model.Feed
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
|
||||
feed = []*model.Feed{}
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
|
@ -37,15 +39,19 @@ func (db *datastore) GetUserFeed(listof []*model.RepoLite) ([]*model.Feed, error
|
|||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
err := meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedQuery, stmt), args...)
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedQuery, stmt), args...)
|
||||
}
|
||||
return feed, err
|
||||
}
|
||||
|
||||
func (db *datastore) GetUserFeedLatest(listof []*model.RepoLite) ([]*model.Feed, error) {
|
||||
var (
|
||||
feed []*model.Feed
|
||||
args []interface{}
|
||||
stmt string
|
||||
err error
|
||||
|
||||
feed = []*model.Feed{}
|
||||
)
|
||||
switch meddler.Default {
|
||||
case meddler.PostgreSQL:
|
||||
|
@ -53,7 +59,9 @@ func (db *datastore) GetUserFeedLatest(listof []*model.RepoLite) ([]*model.Feed,
|
|||
default:
|
||||
stmt, args = toList(listof)
|
||||
}
|
||||
err := meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedLatest, stmt), args...)
|
||||
if len(args) > 0 {
|
||||
err = meddler.QueryAll(db, &feed, fmt.Sprintf(userFeedLatest, stmt), args...)
|
||||
}
|
||||
return feed, err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Bad Request
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger Bad Request
|
|
@ -1,8 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Not Authorized
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger Not Authorized
|
|
@ -1,8 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Forbidden
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger Access Forbidden.
|
|
@ -1,8 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Not Found
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger Not Found
|
|
@ -1,8 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Internal Server Error
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger Oops. Something went wrong.
|
|
@ -1,71 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Dashboard
|
||||
|
||||
block menu
|
||||
li
|
||||
a[href="/"] Home
|
||||
li
|
||||
a[href="/settings/profile"] Profile
|
||||
if User.Admin
|
||||
li
|
||||
a[href="/settings/people"] People
|
||||
li
|
||||
a[href="/settings/nodes"] Nodes
|
||||
|
||||
|
||||
block content
|
||||
h1 Feed
|
||||
hr
|
||||
table
|
||||
tbody[data-bind="foreach: feed"]
|
||||
tr
|
||||
td
|
||||
a[data-bind="text: full_name, attr: {href: full_name() + '/' + number() }"]
|
||||
td[data-bind="text: $data.full_name"]
|
||||
td[data-bind="text: $data.owner"]
|
||||
td[data-bind="text: $data.name"]
|
||||
td[data-bind="text: $data.private"]
|
||||
td[data-bind="text: $data.trusted"]
|
||||
td[data-bind="text: $data.avatar_url"]
|
||||
td[data-bind="text: $data.clone_url"]
|
||||
td[data-bind="text: $data.number"]
|
||||
td[data-bind="text: $data.commit"]
|
||||
td[data-bind="text: $data.branch"]
|
||||
td[data-bind="text: $data.author"]
|
||||
td[data-bind="text: $data.status"]
|
||||
|
||||
block append scripts
|
||||
script
|
||||
var feed = #{json(Feed)};
|
||||
|
||||
function Activity(data) {
|
||||
this.full_name = ko.observable(data.full_name);
|
||||
this.owner = ko.observable(data.owner);
|
||||
this.name = ko.observable(data.name);
|
||||
this.private = ko.observable(data.private);
|
||||
this.trusted = ko.observable(data.trusted);
|
||||
this.avatar_url = ko.observable(data.avatar);
|
||||
this.clone_url = ko.observable(data.clone_url);
|
||||
this.link_url = ko.observable(data.link_url);
|
||||
this.number = ko.observable(data.number);
|
||||
this.commit = ko.observable(data.commit);
|
||||
this.started_at = ko.observable(data.started_at);
|
||||
this.finished_at = ko.observable(data.finished_at);
|
||||
this.exit_code = ko.observable(data.exit_code);
|
||||
this.status = ko.observable(data.status);
|
||||
this.environment = ko.observable(data.environment);
|
||||
}
|
||||
|
||||
function FeedViewModel() {
|
||||
var self = this;
|
||||
|
||||
var mapped = $.map(feed, function(activity) {
|
||||
return new Activity(activity)
|
||||
});
|
||||
|
||||
self.feed = ko.observableArray(mapped);
|
||||
}
|
||||
|
||||
ko.applyBindings(new FeedViewModel());
|
|
@ -1,97 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Users
|
||||
|
||||
block content
|
||||
div.container
|
||||
h1 Users
|
||||
hr
|
||||
form
|
||||
input[type="text"][placeholder="ie octocat"][data-bind="value: newUserLogin"]
|
||||
button[type="button"][data-bind="click: addUser"] add user
|
||||
hr
|
||||
if len(Users) <= 1
|
||||
div.alert.alert-info
|
||||
| You should add users
|
||||
table
|
||||
tbody[data-bind="foreachInit: users"]
|
||||
tr[data-template]
|
||||
td[data-bind="text: $data.login"]
|
||||
td[data-bind="text: $data.email"]
|
||||
td[data-bind="text: $data.avatar_url"]
|
||||
td[data-bind="text: $data.active"]
|
||||
td[data-bind="text: $data.admin"]
|
||||
td
|
||||
button.delete[data-bind="click: $parent.removeUser"] delete
|
||||
td
|
||||
button.delete[data-bind="click: $parent.toggleAdmin"] toggle
|
||||
each $user in Users
|
||||
tr[data-init]
|
||||
td[data-bind="init, text: login"] #{$user.Login}
|
||||
td[data-bind="init, text: email"] #{$user.Email}
|
||||
td[data-bind="init, text: avatar_url"] #{$user.Avatar}
|
||||
td[data-bind="init, text: active"] #{$user.Active}
|
||||
td[data-bind="init, text: admin"] #{$user.Admin}
|
||||
td
|
||||
button.delete[data-bind="init, click: $parent.removeUser"] delete
|
||||
td
|
||||
button.delete[data-bind="init, click: $parent.toggleAdmin"] toggle
|
||||
|
||||
block append scripts
|
||||
script
|
||||
function User(data) {
|
||||
this.login = ko.observable(data.login);
|
||||
this.email = ko.observable(data.email);
|
||||
this.avatar_url = ko.observable(data.avatar_url);
|
||||
this.active = ko.observable(data.active);
|
||||
this.admin = ko.observable(data.admin);
|
||||
}
|
||||
|
||||
function UserViewModel() {
|
||||
var self = this;
|
||||
|
||||
self.users = ko.observableArray();
|
||||
self.newUserLogin = ko.observable();
|
||||
|
||||
self.removeUser = function(user) {
|
||||
$.ajax({
|
||||
url: "/api/users/"+user.login(),
|
||||
type: "DELETE",
|
||||
success: function( data ) {
|
||||
self.users.remove(user);
|
||||
self.users.sort(self.sort);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.addUser = function() {
|
||||
$.ajax({
|
||||
url: "/api/users",
|
||||
type: "POST",
|
||||
data: ko.toJSON({ "login": self.newUserLogin() }),
|
||||
contentType: "application/json",
|
||||
success: function( data ) {
|
||||
self.newUserLogin("");
|
||||
self.users.push(new User(data));
|
||||
self.users.sort(self.sort);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
self.toggleAdmin = function(user) {
|
||||
user.admin(!user.admin());
|
||||
$.ajax({
|
||||
url: "/api/users/"+user.login(),
|
||||
type: "PATCH",
|
||||
data: ko.toJSON(user),
|
||||
contentType: "application/json"
|
||||
});
|
||||
};
|
||||
|
||||
self.sort = function(a, b) {
|
||||
return a.login().toLowerCase() > b.login().toLowerCase() ? 1 : -1;
|
||||
};
|
||||
}
|
||||
|
||||
ko.applyBindings(new UserViewModel());
|
|
@ -1,54 +0,0 @@
|
|||
doctype 5
|
||||
html
|
||||
head
|
||||
block head
|
||||
meta[charset="utf-8"]
|
||||
meta[name="viewport"][content="width=device-width, initial-scale=1"]
|
||||
meta[http-equiv="x-ua-compatible"][content="ie=edge"]
|
||||
link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"]
|
||||
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"]
|
||||
link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"]
|
||||
link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/octicons/3.1.0/octicons.min.css"]
|
||||
link[rel="stylesheet"][href="/static/styles_gen/style.css"]
|
||||
|
||||
if Csrf
|
||||
meta[name="_csrf"][content=Csrf]
|
||||
|
||||
body
|
||||
nav.navbar
|
||||
div.container-fluid
|
||||
a.navbar-brand[href="/"]
|
||||
if User
|
||||
ul.nav.navbar-nav.navbar-right
|
||||
li
|
||||
form.navbar-form
|
||||
input.form-control.typeahead[type="text"][placeholder="Search..."]
|
||||
li
|
||||
img[src=User.Avatar]
|
||||
li
|
||||
div.dropdown
|
||||
button[type="button"][data-toggle="dropdown"]
|
||||
i.material-icons expand_more
|
||||
div.dropdown-menu.dropdown-menu-right
|
||||
a.dropdown-item[href="/settings/profile"] Profile
|
||||
a.dropdown-item[href="/logout"] Logout
|
||||
|
||||
|
||||
div.subnav
|
||||
div.container-fluid
|
||||
block header
|
||||
|
||||
div#content
|
||||
block content
|
||||
|
||||
block scripts
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"]
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"]
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery-searcher/0.2.0/jquery.searcher.min.js"]
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"]
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"]
|
||||
script[text="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/stickyfill/1.1.2/stickyfill.js"]
|
||||
script[type="text/javascript"][src="/static/scripts_gen/drone.min.js"]
|
|
@ -1,99 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title #{Repo.Name} · #{Build.Number}
|
||||
|
||||
|
||||
block header
|
||||
ol
|
||||
li
|
||||
a[href="/"+Repo.FullName]
|
||||
| #{Repo.Owner} / #{Repo.Name}
|
||||
li.separator
|
||||
i.material-icons chevron_right
|
||||
li #{Build.Number}
|
||||
|
||||
|
||||
block content
|
||||
div.container-fluid
|
||||
div.row
|
||||
div.col-md-4.sticky
|
||||
div.build-summary
|
||||
div
|
||||
div[class=Build.Status][style="display:none"] #{Build.Status}
|
||||
h3
|
||||
| #{Build.Message}
|
||||
a.material-icons[href=Build.Link][target="_blank"] link
|
||||
p
|
||||
em #{Build.Author}
|
||||
if Build.Event != "deployment"
|
||||
span authored
|
||||
else
|
||||
span deployed
|
||||
em[data-livestamp=Build.Created]
|
||||
span to
|
||||
if Build.Event != "deployment"
|
||||
em #{Build.Branch}
|
||||
else
|
||||
em #{Build.Deploy}
|
||||
|
||||
|
||||
|
||||
|
||||
div.job-list
|
||||
$curr = Job
|
||||
$build = Build
|
||||
$repo = Repo
|
||||
each $job in Jobs
|
||||
a[href="/" + $repo.FullName +"/"+ $build.Number+"/"+$job.Number][data-job=$job.Number]
|
||||
.active ? $curr.Number == $job.Number
|
||||
div
|
||||
div.status[class=$job.Status] #{$job.Status}
|
||||
div
|
||||
if len($job.Environment) != 0
|
||||
h3
|
||||
each $key, $val in $job.Environment
|
||||
div.env #{$key}=#{$val}
|
||||
div[class="msg-pending"]
|
||||
.hidden ? $job.Status != "pending"
|
||||
| pending assignment to a worker
|
||||
div[class="msg-running"]
|
||||
.hidden ? $job.Status != "running"
|
||||
| started
|
||||
span[data-livestamp=$job.Started]
|
||||
div[class="msg-finished"]
|
||||
.hidden ? $job.Finished == 0
|
||||
| finished
|
||||
span[data-livestamp=$job.Finished]
|
||||
div[class="msg-exited"]
|
||||
.hidden ? $job.Finished == 0
|
||||
| with exit code
|
||||
span #{$job.ExitCode}
|
||||
|
||||
div.build-btn-group
|
||||
button.btn.btn-info.hidden#restart restart
|
||||
button.btn.btn-info.hidden#cancel cancel
|
||||
|
||||
div.col-md-8
|
||||
if Build.Signed
|
||||
if Build.Verified
|
||||
noscript
|
||||
else
|
||||
div.alert.alert-warning
|
||||
| Your .drone.yml.sig file did not match your .drone.yml
|
||||
if Job.Error != ""
|
||||
div.alert.alert-danger #{Job.Error}
|
||||
else
|
||||
div#output
|
||||
button.tail#tail
|
||||
i.material-icons expand_more
|
||||
|
||||
block append scripts
|
||||
script
|
||||
$('.sticky').Stickyfill();
|
||||
var repo = #{json(Repo.FullName)};
|
||||
var build = #{json(Build.Number)};
|
||||
var job = #{json(Job.Number)};
|
||||
var status = #{json(Job.Status)};
|
||||
|
||||
var view = new JobViewModel(repo, build, job, status);
|
|
@ -1,40 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title #{Site.Name} · Drone
|
||||
|
||||
block header
|
||||
ol
|
||||
li Documentation
|
||||
ul.nav.nav-tabs
|
||||
li.nav-item
|
||||
a[class="nav-link"][href="../setup/"]
|
||||
.active ? Site.Name == "Install"
|
||||
| Install
|
||||
li.nav-item
|
||||
a[class="nav-link"][href="../build/"]
|
||||
.active ? Site.Name == "Builds"
|
||||
| Builds
|
||||
li.nav-item
|
||||
a[class="nav-link"][href="../plugin/"]
|
||||
.active ? Site.Name == "Plugins"
|
||||
| Plugins
|
||||
li.nav-item
|
||||
a[class="nav-link"][href="../cli/"]
|
||||
.active ? Site.Name == "CLI"
|
||||
| CLI
|
||||
li.nav-item
|
||||
a.nav-link[href="../api/"] API Reference
|
||||
|
||||
block content
|
||||
div.container-fluid.docs.docs-usage
|
||||
div.row
|
||||
div.content-nav
|
||||
ul
|
||||
#{Site.Nav.HTML}
|
||||
div.content-main
|
||||
#{Page.HTML}
|
||||
|
||||
block scripts
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"]
|
||||
script[type="text/javascript"][src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"]
|
|
@ -1,46 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Active Repositories
|
||||
|
||||
block header
|
||||
ol
|
||||
li Active Repositories
|
||||
|
||||
ul.nav.nav-tabs
|
||||
li.nav-item
|
||||
a.nav-link.active[href="/"] Active Repositories
|
||||
li.nav-item
|
||||
a.nav-link[href="/repos"] Available Repositories
|
||||
|
||||
block content
|
||||
div.container
|
||||
if len(Repos) == 0
|
||||
div.alert.alert-info
|
||||
| Your repository list is empty.
|
||||
|
||||
else
|
||||
div.row.repo-row
|
||||
input.repo-search[type="search"][placeholder="Filter..."]
|
||||
div.repo-list
|
||||
each $repo in Repos
|
||||
div.col-sm-4
|
||||
a.card[href="/"+$repo.FullName]
|
||||
div.card-header
|
||||
if $repo.Avatar != ""
|
||||
img.avatar[src=$repo.Avatar]
|
||||
else
|
||||
img.avatar[src="/static/images/dummy.png"]
|
||||
div.card-block
|
||||
h3.login #{$repo.Name}
|
||||
div.full_name.hidden #{$repo.FullName}
|
||||
block append scripts
|
||||
if len(Repos) != 0
|
||||
script
|
||||
$(window).load(function(){
|
||||
$(".repo-list").searcher({
|
||||
itemSelector: ".col-sm-4",
|
||||
textSelector: ".full_name",
|
||||
inputSelector: ".repo-search"
|
||||
});
|
||||
});
|
|
@ -1,35 +0,0 @@
|
|||
doctype 5
|
||||
html
|
||||
head
|
||||
title Login
|
||||
meta[charset="utf-8"]
|
||||
meta[name="viewport"][content="width=device-width, initial-scale=1"]
|
||||
meta[http-equiv="x-ua-compatible"][content="ie=edge"]
|
||||
link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"]
|
||||
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"]
|
||||
link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"]
|
||||
link[rel="stylesheet"][href="/static/styles_gen/style.css"]
|
||||
style
|
||||
html { height: 100%; overflow: hidden; }
|
||||
|
||||
body.login
|
||||
div
|
||||
div.logo
|
||||
a[href="/authorize"] Login
|
||||
|
||||
if Error == "oauth_error"
|
||||
div.alert.alert-danger
|
||||
| We failed to authorize your account. Please contact your
|
||||
| system administrator to check the logs and see what went wrong.
|
||||
|
||||
else if Error == "access_denied"
|
||||
div.alert.alert-danger
|
||||
| Unable to login. Registration is closed.
|
||||
|
||||
else if Error == "internal_error"
|
||||
div.alert.alert-danger
|
||||
| We encountered an unexpected error. Please contact your
|
||||
| system administrator to check the logs and see what went wrong.
|
|
@ -1,24 +0,0 @@
|
|||
doctype 5
|
||||
html
|
||||
head
|
||||
title Login
|
||||
meta[charset="utf-8"]
|
||||
meta[name="viewport"][content="width=device-width, initial-scale=1"]
|
||||
meta[http-equiv="x-ua-compatible"][content="ie=edge"]
|
||||
link[rel="icon"][type="image/x-icon"][href="/static/images/favicon.ico"]
|
||||
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/icon?family=Material+Icons"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto+Mono"]
|
||||
link[rel="stylesheet"][href="//fonts.googleapis.com/css?family=Roboto"]
|
||||
link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.min.css"]
|
||||
link[rel="stylesheet"][href="/static/styles_gen/style.css"]
|
||||
style
|
||||
html { height: 100%; overflow: hidden; }
|
||||
|
||||
body.login.login-form
|
||||
div
|
||||
div.logo
|
||||
form[action="/authorize"][method="post"]
|
||||
input[type="text"][placeholder="Username"][name="username"]
|
||||
input[type="password"][placeholder="Password"][name="password"]
|
||||
input[type="submit"][value="Login"]
|
|
@ -1,52 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title Docker Nodes
|
||||
|
||||
|
||||
block header
|
||||
ol
|
||||
li Docker Nodes
|
||||
li
|
||||
button.btn.btn-info[data-toggle="modal"][data-target=".modal-node"]
|
||||
| add node
|
||||
|
||||
|
||||
block content
|
||||
div.container
|
||||
div.alert.alert-danger.hidden
|
||||
div.row.node-row
|
||||
each $node in Nodes
|
||||
div.col-sm-4
|
||||
div.card[data-id=$node.ID]
|
||||
div.card-header
|
||||
i[class="linux_amd64"]
|
||||
div.card-block
|
||||
h3.addr #{$node.Addr}
|
||||
p.arch.card-text #{$node.Arch}
|
||||
div.btn-group
|
||||
button.btn.btn-danger Delete
|
||||
|
||||
div.modal.modal-node[role="dialog"]
|
||||
div.modal-dialog
|
||||
div.modal-content
|
||||
form
|
||||
fieldset.form-group
|
||||
label[for="addr"] Address
|
||||
input.form-control[type="text"][placeholder="unix:///var/run/docker.sock"]#addr
|
||||
fieldset.form-group
|
||||
label[for="key"] Key
|
||||
textarea.form-control#key
|
||||
fieldset.form-group
|
||||
label[for="cert"] Cert
|
||||
textarea.form-control#cert
|
||||
fieldset.form-group
|
||||
label[for="ca"] CA
|
||||
textarea.form-control#ca
|
||||
button.btn.btn-info[type="button"] add node
|
||||
|
||||
|
||||
|
||||
block append scripts
|
||||
script
|
||||
var view = new NodeViewModel();
|
|
@ -1,59 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title #{Repo.Name}
|
||||
|
||||
block header
|
||||
ol
|
||||
li #{Repo.Owner} / #{Repo.Name}
|
||||
|
||||
ul.nav.nav-tabs
|
||||
li.nav-item
|
||||
a.nav-link.active[href="/"+Repo.FullName] Builds
|
||||
li.nav-item
|
||||
a.nav-link[href="/"+Repo.FullName+"/settings/badges"] Badges
|
||||
li.nav-item
|
||||
a.nav-link[href="/"+Repo.FullName+"/settings/encrypt"] Secrets
|
||||
li.nav-item
|
||||
a.nav-link[href="/"+Repo.FullName+"/settings"] Settings
|
||||
|
||||
block content
|
||||
div.container
|
||||
if len(Builds) == 0
|
||||
div.alert.alert-info
|
||||
| You have no builds
|
||||
|
||||
div.timeline
|
||||
$repo = Repo
|
||||
each $group in Groups
|
||||
div.group
|
||||
div.group-title
|
||||
| commits on #{$group.Date}
|
||||
each $build in $group.Builds
|
||||
a.card[href=$repo.Name+"/"+$build.Number][data-build=$build.Number]
|
||||
div.card-header
|
||||
if $build.Avatar != ""
|
||||
img[src=$build.Avatar]
|
||||
else
|
||||
img[src="/static/images/dummy.png"]
|
||||
div.card-block
|
||||
div
|
||||
div.status[class=$build.Status] #{$build.Status}
|
||||
h3 #{$build.Message}
|
||||
p.card-text
|
||||
em #{$build.Author}
|
||||
if $build.Event != "deployment"
|
||||
span authored
|
||||
else
|
||||
span deployed
|
||||
em[data-livestamp=$build.Created]
|
||||
span to
|
||||
if $build.Event != "deployment"
|
||||
em #{$build.Branch}
|
||||
else
|
||||
em #{$build.Deploy}
|
||||
|
||||
|
||||
block append scripts
|
||||
script
|
||||
new RepoViewModel("#{Repo.FullName}");
|
|
@ -1,33 +0,0 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title #{Repo.Name}
|
||||
|
||||
block header
|
||||
ol
|
||||
li #{Repo.Owner} / #{Repo.Name}
|
||||
|
||||
block content
|
||||
div.container.repo_activate
|
||||
div.alert.alert-danger.hidden
|
||||
div.alert.alert-info
|
||||
| This repository is not yet activated.
|
||||
button.btn.btn-info#activateRepo Activate Now
|
||||
|
||||
|
||||
block append scripts
|
||||
script
|
||||
$( "#activateRepo" ).click(function() {
|
||||
$( "#activateRepo" ).hide();
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/api/repos/#{Repo.FullName}",
|
||||
success: function() {
|
||||
window.location.href="/#{Repo.FullName}"
|
||||
},
|
||||
error: function(err) {
|
||||
$(".alert-info").hide();
|
||||
$(".alert-danger").text("Unable to activate this repository. You must have administrative access to this repository. Also, please check the third-party application access policy to ensure Drone is approved. "+ err.responseText).show();
|
||||
}
|
||||
});
|
||||
});
|