mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
625ca8215e | |||
9e735eb47e | |||
9766d8e903 | |||
39c4777fc8 | |||
143c80b7b4 | |||
72e42a9c42 | |||
439a87dec9 |
@ -1 +1,6 @@
|
|||||||
.env
|
.env
|
||||||
|
config*.yml
|
||||||
|
!config.default.yml
|
||||||
|
*.db
|
||||||
|
*.exe
|
||||||
|
wakapi
|
19
Dockerfile
19
Dockerfile
@ -1,6 +1,6 @@
|
|||||||
# Build Stage
|
# Build Stage
|
||||||
|
|
||||||
FROM golang:1.13 AS build-env
|
FROM golang:1.15 AS build-env
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
ADD ./go.mod .
|
ADD ./go.mod .
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
@ -8,19 +8,11 @@ RUN go mod download
|
|||||||
ADD . .
|
ADD . .
|
||||||
RUN go build -o wakapi
|
RUN go build -o wakapi
|
||||||
|
|
||||||
# Final Stage
|
# Run Stage
|
||||||
|
|
||||||
# When running the application using `docker run`, you can pass environment variables
|
# When running the application using `docker run`, you can pass environment variables
|
||||||
# to override config values using `-e` syntax.
|
# to override config values using `-e` syntax.
|
||||||
# Available options are:
|
# Available options can be found in [README.md#-configuration](README.md#-configuration)
|
||||||
# – WAKAPI_DB_TYPE
|
|
||||||
# – WAKAPI_DB_USER
|
|
||||||
# – WAKAPI_DB_PASSWORD
|
|
||||||
# – WAKAPI_DB_HOST
|
|
||||||
# – WAKAPI_DB_PORT
|
|
||||||
# – WAKAPI_DB_NAME
|
|
||||||
# – WAKAPI_PASSWORD_SALT
|
|
||||||
# – WAKAPI_BASE_PATH
|
|
||||||
|
|
||||||
FROM debian
|
FROM debian
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@ -32,13 +24,14 @@ ENV WAKAPI_DB_PASSWORD ''
|
|||||||
ENV WAKAPI_DB_HOST ''
|
ENV WAKAPI_DB_HOST ''
|
||||||
ENV WAKAPI_DB_NAME=/data/wakapi.db
|
ENV WAKAPI_DB_NAME=/data/wakapi.db
|
||||||
ENV WAKAPI_PASSWORD_SALT ''
|
ENV WAKAPI_PASSWORD_SALT ''
|
||||||
|
ENV WAKAPI_LISTEN_IPV4 '0.0.0.0'
|
||||||
|
ENV WAKAPI_INSECURE_COOKIES 'true'
|
||||||
|
|
||||||
COPY --from=build-env /src/wakapi /app/
|
COPY --from=build-env /src/wakapi /app/
|
||||||
COPY --from=build-env /src/config.default.yml /app/config.yml
|
COPY --from=build-env /src/config.default.yml /app/config.yml
|
||||||
COPY --from=build-env /src/version.txt /app/
|
COPY --from=build-env /src/version.txt /app/
|
||||||
|
|
||||||
RUN sed -i 's/listen_ipv4: 127.0.0.1/listen_ipv4: 0.0.0.0/g' /app/config.yml
|
RUN sed -i 's/listen_ipv6: ::1/listen_ipv6: /g' /app/config.yml
|
||||||
RUN sed -i 's/insecure_cookies: false/insecure_cookies: true/g' /app/config.yml
|
|
||||||
|
|
||||||
ADD static /app/static
|
ADD static /app/static
|
||||||
ADD data /app/data
|
ADD data /app/data
|
||||||
|
24
README.md
24
README.md
@ -21,9 +21,10 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
If you like this project, please consider supporting it 🙂. You can donate either through [buying me a coffee](https://buymeacoff.ee/n1try) or becoming a GitHub sponsor. Every little donation is highly appreciated and boosts the developers' motivation to keep improving Wakapi!
|
## 📬 **User Survey**
|
||||||
|
I'd love to get some community feedback from active Wakapi users. If you like, please participate in the recent [user survey](https://github.com/muety/wakapi/issues/82). Thanks a lot!
|
||||||
|
|
||||||
## 👀 Hosted Service
|
## 👀 Demo
|
||||||
🔥 **New:** Wakapi is available as a hosted service now. Check out **[wakapi.dev](https://wakapi.dev)**. Please use responsibly.
|
🔥 **New:** Wakapi is available as a hosted service now. Check out **[wakapi.dev](https://wakapi.dev)**. Please use responsibly.
|
||||||
|
|
||||||
To use the hosted version set `api_url = https://wakapi.dev/api/heartbeat`. However, we do not guarantee data persistence, so you might potentially lose your data if the service is taken down some day ❕
|
To use the hosted version set `api_url = https://wakapi.dev/api/heartbeat`. However, we do not guarantee data persistence, so you might potentially lose your data if the service is taken down some day ❕
|
||||||
@ -53,14 +54,14 @@ To use the hosted version set `api_url = https://wakapi.dev/api/heartbeat`. Howe
|
|||||||
|
|
||||||
### Run with Docker
|
### Run with Docker
|
||||||
```bash
|
```bash
|
||||||
docker run -d -p 3000:3000 --name wakapi n1try/wakapi
|
docker run -d -p 3000:3000 -e "WAKAPI_PASSWORD_SALT=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-32} | head -n 1)" --name wakapi n1try/wakapi
|
||||||
```
|
```
|
||||||
|
|
||||||
By default, SQLite is used as a database. To run Wakapi in Docker with MySQL or Postgres, see [Dockerfile](https://github.com/muety/wakapi/blob/master/Dockerfile) and [config.default.yml](https://github.com/muety/wakapi/blob/master/config.default.yml) for further options.
|
By default, SQLite is used as a database. To run Wakapi in Docker with MySQL or Postgres, see [Dockerfile](https://github.com/muety/wakapi/blob/master/Dockerfile) and [config.default.yml](https://github.com/muety/wakapi/blob/master/config.default.yml) for further options.
|
||||||
|
|
||||||
### Running tests
|
### Running tests
|
||||||
```bash
|
```bash
|
||||||
CGO_FLAGS="-g -O2 -Wno-return-local-addr" -coverprofile=coverage/coverage.out go test ./...
|
CGO_FLAGS="-g -O2 -Wno-return-local-addr" go test -json -coverprofile=coverage/coverage.out ./... -run ./...
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔧 Configuration
|
## 🔧 Configuration
|
||||||
@ -71,12 +72,14 @@ You can specify configuration options either via a config file (default: `config
|
|||||||
| `env` | `ENVIRONMENT` | `dev` | Whether to use development- or production settings |
|
| `env` | `ENVIRONMENT` | `dev` | Whether to use development- or production settings |
|
||||||
| `app.custom_languages` | - | - | Map from file endings to language names |
|
| `app.custom_languages` | - | - | Map from file endings to language names |
|
||||||
| `server.port` | `WAKAPI_PORT` | `3000` | Port to listen on |
|
| `server.port` | `WAKAPI_PORT` | `3000` | Port to listen on |
|
||||||
| `server.listen_ipv4` | `WAKAPI_LISTEN_IPV4` | `127.0.0.1` | Network address to listen on |
|
| `server.listen_ipv4` | `WAKAPI_LISTEN_IPV4` | `127.0.0.1` | IPv4 network address to listen on (leave blank to disable IPv4) |
|
||||||
|
| `server.listen_ipv6` | `WAKAPI_LISTEN_IPV6` | `::1` | IPv6 network address to listen on (leave blank to disable IPv6) |
|
||||||
|
| `server.tls_cert_path` | `WAKAPI_TLS_CERT_PATH` | - | Path of SSL server certificate (leave blank to not use HTTPS) |
|
||||||
|
| `server.tls_key_path` | `WAKAPI_TLS_KEY_PATH` | - | Path of SSL server private key (leave blank to not use HTTPS) |
|
||||||
| `server.base_path` | `WAKAPI_BASE_PATH` | `/` | Web base path (change when running behind a proxy under a sub-path) |
|
| `server.base_path` | `WAKAPI_BASE_PATH` | `/` | Web base path (change when running behind a proxy under a sub-path) |
|
||||||
| `security.password_salt` | `WAKAPI_PASSWORD_SALT` | - | Pepper to use for password hashing |
|
| `security.password_salt` | `WAKAPI_PASSWORD_SALT` | - | Pepper to use for password hashing |
|
||||||
| `security.insecure_cookies` | `WAKAPI_INSECURE_COOKIES` | `false` | Whether or not to allow cookies over HTTP |
|
| `security.insecure_cookies` | `WAKAPI_INSECURE_COOKIES` | `false` | Whether or not to allow cookies over HTTP |
|
||||||
| `security.cookie_max_age` | `WAKAPI_COOKIE_MAX_AGE ` | `172800` | Lifetime of authentication cookies in seconds or `0` to use [Session](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Define_the_lifetime_of_a_cookie) cookies
|
| `security.cookie_max_age` | `WAKAPI_COOKIE_MAX_AGE ` | `172800` | Lifetime of authentication cookies in seconds or `0` to use [Session](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#Define_the_lifetime_of_a_cookie) cookies |
|
||||||
|
|
|
||||||
| `db.host` | `WAKAPI_DB_HOST` | - | Database host |
|
| `db.host` | `WAKAPI_DB_HOST` | - | Database host |
|
||||||
| `db.port` | `WAKAPI_DB_PORT` | - | Database port |
|
| `db.port` | `WAKAPI_DB_PORT` | - | Database port |
|
||||||
| `db.user` | `WAKAPI_DB_USER` | - | Database user |
|
| `db.user` | `WAKAPI_DB_USER` | - | Database user |
|
||||||
@ -98,6 +101,10 @@ api_key = the_api_key_printed_to_the_console_after_starting_the_server`
|
|||||||
|
|
||||||
You can view your API Key after logging in to the web interface.
|
You can view your API Key after logging in to the web interface.
|
||||||
|
|
||||||
|
### Optional: Client-side proxy
|
||||||
|
|
||||||
|
See the [advanced setup instructions](docs/advanced_setup.md).
|
||||||
|
|
||||||
## 🔵 Customization
|
## 🔵 Customization
|
||||||
|
|
||||||
### Aliases
|
### Aliases
|
||||||
@ -142,6 +149,9 @@ We recently introduced support for [Shields.io](https://shields.io) badges (see
|
|||||||
It is recommended to use wakapi behind a **reverse proxy**, like [Caddy](https://caddyserver.com) or _nginx_ to enable **TLS encryption** (HTTPS).
|
It is recommended to use wakapi behind a **reverse proxy**, like [Caddy](https://caddyserver.com) or _nginx_ to enable **TLS encryption** (HTTPS).
|
||||||
However, if you want to expose your wakapi instance to the public anyway, you need to set `server.listen_ipv4` to `0.0.0.0` in `config.yml`
|
However, if you want to expose your wakapi instance to the public anyway, you need to set `server.listen_ipv4` to `0.0.0.0` in `config.yml`
|
||||||
|
|
||||||
|
## 🙏 Support
|
||||||
|
If you like this project, please consider supporting it 🙂. You can donate either through [buying me a coffee](https://buymeacoff.ee/n1try) or becoming a GitHub sponsor. Every little donation is highly appreciated and boosts the developers' motivation to keep improving Wakapi!
|
||||||
|
|
||||||
## ⚠️ Important Note
|
## ⚠️ Important Note
|
||||||
**This is not an alternative to using WakaTime.** It is just a custom, non-commercial, self-hosted application to collect coding statistics using the already existing editor plugins provided by the WakaTime community. It was created for personal use only and with the purpose of keeping the sovereignity of your own data. However, if you like the official product, **please support the authors and buy an official WakaTime subscription!**
|
**This is not an alternative to using WakaTime.** It is just a custom, non-commercial, self-hosted application to collect coding statistics using the already existing editor plugins provided by the WakaTime community. It was created for personal use only and with the purpose of keeping the sovereignity of your own data. However, if you like the official product, **please support the authors and buy an official WakaTime subscription!**
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
env: development
|
env: development
|
||||||
|
|
||||||
server:
|
server:
|
||||||
listen_ipv4: 127.0.0.1
|
listen_ipv4: 127.0.0.1 # leave blank to disable ipv4
|
||||||
|
listen_ipv6: ::1 # leave blank to disable ipv6
|
||||||
|
tls_cert_path: # leave blank to not use https
|
||||||
|
tls_key_path: # leave blank to not use https
|
||||||
port: 3000
|
port: 3000
|
||||||
base_path: /
|
base_path: /
|
||||||
|
|
||||||
|
@ -57,9 +57,12 @@ type dbConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type serverConfig struct {
|
type serverConfig struct {
|
||||||
Port int `default:"3000" env:"WAKAPI_PORT"`
|
Port int `default:"3000" env:"WAKAPI_PORT"`
|
||||||
ListenIpV4 string `yaml:"listen_ipv4" default:"127.0.0.1" env:"WAKAPI_LISTEN_IPV4"`
|
ListenIpV4 string `yaml:"listen_ipv4" default:"127.0.0.1" env:"WAKAPI_LISTEN_IPV4"`
|
||||||
BasePath string `yaml:"base_path" default:"/" env:"WAKAPI_BASE_PATH"`
|
ListenIpV6 string `yaml:"listen_ipv6" default:"::1" env:"WAKAPI_LISTEN_IPV6"`
|
||||||
|
BasePath string `yaml:"base_path" default:"/" env:"WAKAPI_BASE_PATH"`
|
||||||
|
TlsCertPath string `yaml:"tls_cert_path" default:"" env:"WAKAPI_TLS_CERT_PATH"`
|
||||||
|
TlsKeyPath string `yaml:"tls_key_path" default:"" env:"WAKAPI_TLS_KEY_PATH"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -95,6 +98,10 @@ func (c *Config) IsDev() bool {
|
|||||||
return IsDev(c.Env)
|
return IsDev(c.Env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) UseTLS() bool {
|
||||||
|
return c.Server.TlsCertPath != "" && c.Server.TlsKeyPath != ""
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) GetMigrationFunc(dbDialect string) models.MigrationFunc {
|
func (c *Config) GetMigrationFunc(dbDialect string) models.MigrationFunc {
|
||||||
switch dbDialect {
|
switch dbDialect {
|
||||||
default:
|
default:
|
||||||
@ -172,6 +179,14 @@ func sqliteConnectionString(config *dbConfig) string {
|
|||||||
return config.Name
|
return config.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *appConfig) GetCustomLanguages() map[string]string {
|
||||||
|
return cloneStringMap(c.CustomLanguages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *appConfig) GetLanguageColors() map[string]string {
|
||||||
|
return cloneStringMap(c.LanguageColors)
|
||||||
|
}
|
||||||
|
|
||||||
func IsDev(env string) bool {
|
func IsDev(env string) bool {
|
||||||
return env == "dev" || env == "development"
|
return env == "dev" || env == "development"
|
||||||
}
|
}
|
||||||
@ -260,6 +275,10 @@ func Load() *Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Server.ListenIpV4 == "" && config.Server.ListenIpV6 == "" {
|
||||||
|
log.Fatalln("either of listen_ipv4 or listen_ipv6 must be set")
|
||||||
|
}
|
||||||
|
|
||||||
Set(config)
|
Set(config)
|
||||||
return Get()
|
return Get()
|
||||||
}
|
}
|
||||||
|
9
config/utils.go
Normal file
9
config/utils.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
func cloneStringMap(m map[string]string) map[string]string {
|
||||||
|
m2 := make(map[string]string)
|
||||||
|
for k, v := range m {
|
||||||
|
m2[k] = v
|
||||||
|
}
|
||||||
|
return m2
|
||||||
|
}
|
@ -1,4 +1,18 @@
|
|||||||
mode: set
|
mode: set
|
||||||
|
github.com/muety/wakapi/models/shared.go:34.52,37.16 3 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:40.2,42.12 3 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:37.16,39.3 1 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:46.52,52.22 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:68.2,71.12 3 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:53.14,55.17 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:58.13,60.8 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:61.17,63.8 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:64.10,65.64 1 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:55.17,57.4 1 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:74.51,77.2 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:79.37,82.2 2 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:84.35,86.2 1 0
|
||||||
|
github.com/muety/wakapi/models/shared.go:88.34,90.2 1 0
|
||||||
github.com/muety/wakapi/models/filters.go:16.56,17.16 1 0
|
github.com/muety/wakapi/models/filters.go:16.56,17.16 1 0
|
||||||
github.com/muety/wakapi/models/filters.go:29.2,29.19 1 0
|
github.com/muety/wakapi/models/filters.go:29.2,29.19 1 0
|
||||||
github.com/muety/wakapi/models/filters.go:18.22,19.32 1 0
|
github.com/muety/wakapi/models/filters.go:18.22,19.32 1 0
|
||||||
@ -28,6 +42,17 @@ github.com/muety/wakapi/models/filters.go:53.20,55.3 1 0
|
|||||||
github.com/muety/wakapi/models/filters.go:56.22,58.3 1 1
|
github.com/muety/wakapi/models/filters.go:56.22,58.3 1 1
|
||||||
github.com/muety/wakapi/models/filters.go:59.21,61.3 1 0
|
github.com/muety/wakapi/models/filters.go:59.21,61.3 1 0
|
||||||
github.com/muety/wakapi/models/filters.go:62.16,64.3 1 0
|
github.com/muety/wakapi/models/filters.go:62.16,64.3 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:7.31,9.2 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:11.41,13.2 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:15.36,17.2 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:19.43,22.2 2 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:24.41,26.18 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:29.2,29.16 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:26.18,28.3 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:32.40,34.18 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:37.2,37.24 1 0
|
||||||
|
github.com/muety/wakapi/models/heartbeats.go:34.18,36.3 1 0
|
||||||
|
github.com/muety/wakapi/models/models.go:3.14,5.2 0 1
|
||||||
github.com/muety/wakapi/models/heartbeat.go:26.34,28.2 1 1
|
github.com/muety/wakapi/models/heartbeat.go:26.34,28.2 1 1
|
||||||
github.com/muety/wakapi/models/heartbeat.go:30.65,31.28 1 1
|
github.com/muety/wakapi/models/heartbeat.go:30.65,31.28 1 1
|
||||||
github.com/muety/wakapi/models/heartbeat.go:34.2,35.45 2 1
|
github.com/muety/wakapi/models/heartbeat.go:34.2,35.45 2 1
|
||||||
@ -45,10 +70,12 @@ github.com/muety/wakapi/models/heartbeat.go:51.23,52.19 1 1
|
|||||||
github.com/muety/wakapi/models/heartbeat.go:53.17,54.26 1 1
|
github.com/muety/wakapi/models/heartbeat.go:53.17,54.26 1 1
|
||||||
github.com/muety/wakapi/models/heartbeat.go:55.22,56.18 1 1
|
github.com/muety/wakapi/models/heartbeat.go:55.22,56.18 1 1
|
||||||
github.com/muety/wakapi/models/heartbeat.go:59.15,61.3 1 1
|
github.com/muety/wakapi/models/heartbeat.go:59.15,61.3 1 1
|
||||||
github.com/muety/wakapi/models/models.go:3.14,5.2 0 1
|
github.com/muety/wakapi/models/language_mapping.go:11.42,13.2 1 0
|
||||||
|
github.com/muety/wakapi/models/language_mapping.go:15.51,17.2 1 0
|
||||||
|
github.com/muety/wakapi/models/language_mapping.go:19.52,21.2 1 0
|
||||||
github.com/muety/wakapi/models/summary.go:29.27,33.2 1 0
|
github.com/muety/wakapi/models/summary.go:29.27,33.2 1 0
|
||||||
github.com/muety/wakapi/models/summary.go:83.29,85.2 1 1
|
github.com/muety/wakapi/models/summary.go:83.29,85.2 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:87.37,94.2 6 0
|
github.com/muety/wakapi/models/summary.go:87.37,94.2 6 1
|
||||||
github.com/muety/wakapi/models/summary.go:96.35,98.2 1 1
|
github.com/muety/wakapi/models/summary.go:96.35,98.2 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:100.57,108.2 1 1
|
github.com/muety/wakapi/models/summary.go:100.57,108.2 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:121.33,126.26 4 1
|
github.com/muety/wakapi/models/summary.go:121.33,126.26 4 1
|
||||||
@ -93,40 +120,100 @@ github.com/muety/wakapi/models/summary.go:216.31,218.60 1 1
|
|||||||
github.com/muety/wakapi/models/summary.go:218.60,219.55 1 1
|
github.com/muety/wakapi/models/summary.go:218.60,219.55 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:219.55,221.6 1 1
|
github.com/muety/wakapi/models/summary.go:219.55,221.6 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:221.11,229.6 1 1
|
github.com/muety/wakapi/models/summary.go:221.11,229.6 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:246.33,248.2 1 0
|
github.com/muety/wakapi/models/summary.go:246.33,248.2 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:250.43,252.2 1 0
|
github.com/muety/wakapi/models/summary.go:250.43,252.2 1 1
|
||||||
github.com/muety/wakapi/models/summary.go:254.38,256.2 1 0
|
github.com/muety/wakapi/models/summary.go:254.38,256.2 1 1
|
||||||
github.com/muety/wakapi/models/user.go:34.43,37.2 1 0
|
github.com/muety/wakapi/models/user.go:34.43,37.2 1 0
|
||||||
github.com/muety/wakapi/models/user.go:39.33,43.2 1 0
|
github.com/muety/wakapi/models/user.go:39.33,43.2 1 0
|
||||||
github.com/muety/wakapi/models/user.go:45.45,47.2 1 0
|
github.com/muety/wakapi/models/user.go:45.45,47.2 1 0
|
||||||
github.com/muety/wakapi/models/user.go:49.45,51.2 1 0
|
github.com/muety/wakapi/models/user.go:49.45,51.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:7.31,9.2 1 0
|
github.com/muety/wakapi/config/config.go:77.70,79.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:11.41,13.2 1 0
|
github.com/muety/wakapi/config/config.go:81.65,83.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:15.36,17.2 1 0
|
github.com/muety/wakapi/config/config.go:85.82,95.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:19.43,22.2 2 0
|
github.com/muety/wakapi/config/config.go:97.31,99.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:24.41,26.18 1 0
|
github.com/muety/wakapi/config/config.go:101.32,103.2 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:29.2,29.16 1 0
|
github.com/muety/wakapi/config/config.go:105.74,106.19 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:26.18,28.3 1 0
|
github.com/muety/wakapi/config/config.go:107.10,108.34 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:32.40,34.18 1 0
|
github.com/muety/wakapi/config/config.go:108.34,117.4 8 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:37.2,37.24 1 0
|
github.com/muety/wakapi/config/config.go:121.73,122.33 1 0
|
||||||
github.com/muety/wakapi/models/heartbeats.go:34.18,36.3 1 0
|
github.com/muety/wakapi/config/config.go:122.33,130.17 5 0
|
||||||
github.com/muety/wakapi/models/language_mapping.go:11.42,13.2 1 0
|
github.com/muety/wakapi/config/config.go:134.3,135.13 2 0
|
||||||
github.com/muety/wakapi/models/language_mapping.go:15.51,17.2 1 0
|
github.com/muety/wakapi/config/config.go:130.17,132.4 1 0
|
||||||
github.com/muety/wakapi/models/language_mapping.go:19.52,21.2 1 0
|
github.com/muety/wakapi/config/config.go:139.50,140.19 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:34.52,37.16 3 0
|
github.com/muety/wakapi/config/config.go:153.2,153.12 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:40.2,42.12 3 0
|
github.com/muety/wakapi/config/config.go:141.23,145.5 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:37.16,39.3 1 0
|
github.com/muety/wakapi/config/config.go:146.26,149.5 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:46.52,52.22 2 0
|
github.com/muety/wakapi/config/config.go:150.24,151.48 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:68.2,71.12 3 0
|
github.com/muety/wakapi/config/config.go:156.53,166.2 1 1
|
||||||
github.com/muety/wakapi/models/shared.go:53.14,55.17 2 0
|
github.com/muety/wakapi/config/config.go:168.56,176.2 1 1
|
||||||
github.com/muety/wakapi/models/shared.go:58.13,60.8 2 0
|
github.com/muety/wakapi/config/config.go:178.54,180.2 1 1
|
||||||
github.com/muety/wakapi/models/shared.go:61.17,63.8 2 0
|
github.com/muety/wakapi/config/config.go:182.60,184.2 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:64.10,65.64 1 0
|
github.com/muety/wakapi/config/config.go:186.59,188.2 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:55.17,57.4 1 0
|
github.com/muety/wakapi/config/config.go:190.29,192.2 1 1
|
||||||
github.com/muety/wakapi/models/shared.go:74.51,77.2 2 0
|
github.com/muety/wakapi/config/config.go:194.27,196.16 2 0
|
||||||
github.com/muety/wakapi/models/shared.go:79.37,82.2 2 0
|
github.com/muety/wakapi/config/config.go:199.2,202.16 3 0
|
||||||
github.com/muety/wakapi/models/shared.go:84.35,86.2 1 0
|
github.com/muety/wakapi/config/config.go:206.2,206.22 1 0
|
||||||
github.com/muety/wakapi/models/shared.go:88.34,90.2 1 0
|
github.com/muety/wakapi/config/config.go:196.16,198.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:202.16,204.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:209.45,219.16 4 0
|
||||||
|
github.com/muety/wakapi/config/config.go:223.2,223.57 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:227.2,227.30 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:231.2,231.15 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:219.16,221.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:223.57,225.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:227.30,229.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:234.38,235.43 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:239.2,239.15 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:235.43,237.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:242.26,244.2 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:246.20,248.2 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:250.21,257.96 4 0
|
||||||
|
github.com/muety/wakapi/config/config.go:261.2,268.52 4 0
|
||||||
|
github.com/muety/wakapi/config/config.go:272.2,272.47 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:278.2,278.70 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:282.2,283.14 2 0
|
||||||
|
github.com/muety/wakapi/config/config.go:257.96,259.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:268.52,270.3 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:272.47,273.14 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:273.14,275.4 1 0
|
||||||
|
github.com/muety/wakapi/config/config.go:278.70,280.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:13.33,14.57 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:14.57,16.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:16.8,16.16 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:16.16,18.47 2 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:21.3,21.128 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:18.47,20.4 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:25.48,26.54 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:31.2,31.18 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:26.54,28.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:28.8,28.32 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:28.32,30.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:34.34,37.16 2 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:40.2,41.16 2 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:45.2,57.16 11 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:61.2,61.18 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:65.2,69.16 5 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:73.2,75.23 3 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:80.2,82.33 3 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:87.2,114.16 3 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:119.2,119.78 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:123.2,123.12 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:37.16,39.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:41.16,43.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:57.16,59.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:61.18,63.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:69.16,71.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:75.23,77.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:82.33,84.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:114.16,116.3 1 0
|
||||||
|
github.com/muety/wakapi/config/legacy.go:119.78,121.3 1 0
|
||||||
|
github.com/muety/wakapi/config/utils.go:3.60,5.22 2 0
|
||||||
|
github.com/muety/wakapi/config/utils.go:8.2,8.11 1 0
|
||||||
|
github.com/muety/wakapi/config/utils.go:5.22,7.3 1 0
|
||||||
|
github.com/muety/wakapi/utils/color.go:8.93,10.41 2 0
|
||||||
|
github.com/muety/wakapi/utils/color.go:15.2,15.15 1 0
|
||||||
|
github.com/muety/wakapi/utils/color.go:10.41,11.50 1 0
|
||||||
|
github.com/muety/wakapi/utils/color.go:11.50,13.4 1 0
|
||||||
github.com/muety/wakapi/utils/common.go:9.48,11.2 1 0
|
github.com/muety/wakapi/utils/common.go:9.48,11.2 1 0
|
||||||
github.com/muety/wakapi/utils/common.go:13.40,15.2 1 0
|
github.com/muety/wakapi/utils/common.go:13.40,15.2 1 0
|
||||||
github.com/muety/wakapi/utils/common.go:17.45,19.2 1 0
|
github.com/muety/wakapi/utils/common.go:17.45,19.2 1 0
|
||||||
@ -202,85 +289,6 @@ github.com/muety/wakapi/utils/auth.go:77.55,80.16 3 0
|
|||||||
github.com/muety/wakapi/utils/auth.go:83.2,83.16 1 0
|
github.com/muety/wakapi/utils/auth.go:83.2,83.16 1 0
|
||||||
github.com/muety/wakapi/utils/auth.go:80.16,82.3 1 0
|
github.com/muety/wakapi/utils/auth.go:80.16,82.3 1 0
|
||||||
github.com/muety/wakapi/utils/auth.go:86.43,91.2 4 0
|
github.com/muety/wakapi/utils/auth.go:86.43,91.2 4 0
|
||||||
github.com/muety/wakapi/utils/color.go:8.93,10.41 2 0
|
|
||||||
github.com/muety/wakapi/utils/color.go:15.2,15.15 1 0
|
|
||||||
github.com/muety/wakapi/utils/color.go:10.41,11.50 1 0
|
|
||||||
github.com/muety/wakapi/utils/color.go:11.50,13.4 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:74.70,76.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:78.65,80.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:82.82,92.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:94.31,96.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:98.74,99.19 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:100.10,101.34 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:101.34,110.4 8 0
|
|
||||||
github.com/muety/wakapi/config/config.go:114.73,115.33 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:115.33,123.17 5 0
|
|
||||||
github.com/muety/wakapi/config/config.go:127.3,128.13 2 0
|
|
||||||
github.com/muety/wakapi/config/config.go:123.17,125.4 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:132.50,133.19 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:146.2,146.12 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:134.23,138.5 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:139.26,142.5 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:143.24,144.48 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:149.53,159.2 1 1
|
|
||||||
github.com/muety/wakapi/config/config.go:161.56,169.2 1 1
|
|
||||||
github.com/muety/wakapi/config/config.go:171.54,173.2 1 1
|
|
||||||
github.com/muety/wakapi/config/config.go:175.29,177.2 1 1
|
|
||||||
github.com/muety/wakapi/config/config.go:179.27,181.16 2 0
|
|
||||||
github.com/muety/wakapi/config/config.go:184.2,187.16 3 0
|
|
||||||
github.com/muety/wakapi/config/config.go:191.2,191.22 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:181.16,183.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:187.16,189.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:194.45,204.16 4 0
|
|
||||||
github.com/muety/wakapi/config/config.go:208.2,208.57 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:212.2,212.30 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:216.2,216.15 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:204.16,206.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:208.57,210.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:212.30,214.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:219.38,220.43 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:224.2,224.15 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:220.43,222.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:227.26,229.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:231.20,233.2 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:235.21,242.96 4 0
|
|
||||||
github.com/muety/wakapi/config/config.go:246.2,253.52 4 0
|
|
||||||
github.com/muety/wakapi/config/config.go:257.2,257.47 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:263.2,264.14 2 0
|
|
||||||
github.com/muety/wakapi/config/config.go:242.96,244.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:253.52,255.3 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:257.47,258.14 1 0
|
|
||||||
github.com/muety/wakapi/config/config.go:258.14,260.4 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:13.33,14.57 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:14.57,16.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:16.8,16.16 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:16.16,18.47 2 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:21.3,21.128 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:18.47,20.4 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:25.48,26.54 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:31.2,31.18 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:26.54,28.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:28.8,28.32 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:28.32,30.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:34.34,37.16 2 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:40.2,41.16 2 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:45.2,57.16 11 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:61.2,61.18 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:65.2,69.16 5 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:73.2,75.23 3 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:80.2,82.33 3 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:87.2,114.16 3 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:119.2,119.78 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:123.2,123.12 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:37.16,39.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:41.16,43.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:57.16,59.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:61.18,63.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:69.16,71.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:75.23,77.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:82.33,84.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:114.16,116.3 1 0
|
|
||||||
github.com/muety/wakapi/config/legacy.go:119.78,121.3 1 0
|
|
||||||
github.com/muety/wakapi/middlewares/authenticate.go:27.116,34.2 1 1
|
github.com/muety/wakapi/middlewares/authenticate.go:27.116,34.2 1 1
|
||||||
github.com/muety/wakapi/middlewares/authenticate.go:36.71,37.71 1 0
|
github.com/muety/wakapi/middlewares/authenticate.go:36.71,37.71 1 0
|
||||||
github.com/muety/wakapi/middlewares/authenticate.go:37.71,39.3 1 0
|
github.com/muety/wakapi/middlewares/authenticate.go:37.71,39.3 1 0
|
||||||
@ -320,44 +328,44 @@ github.com/muety/wakapi/middlewares/logging.go:11.48,13.2 1 0
|
|||||||
github.com/muety/wakapi/middlewares/logging.go:15.66,17.2 1 0
|
github.com/muety/wakapi/middlewares/logging.go:15.66,17.2 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:24.142,31.2 1 0
|
github.com/muety/wakapi/services/aggregation.go:24.142,31.2 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:40.43,42.37 1 0
|
github.com/muety/wakapi/services/aggregation.go:40.43,42.37 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:46.2,47.18 2 0
|
github.com/muety/wakapi/services/aggregation.go:46.2,48.19 3 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:42.37,44.3 1 0
|
github.com/muety/wakapi/services/aggregation.go:42.37,44.3 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:50.67,54.40 3 0
|
github.com/muety/wakapi/services/aggregation.go:51.67,55.40 3 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:58.2,58.50 1 0
|
github.com/muety/wakapi/services/aggregation.go:59.2,59.50 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:63.2,63.60 1 0
|
github.com/muety/wakapi/services/aggregation.go:64.2,64.60 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:69.2,69.35 1 0
|
github.com/muety/wakapi/services/aggregation.go:70.2,70.35 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:54.40,56.3 1 0
|
github.com/muety/wakapi/services/aggregation.go:55.40,57.3 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:58.50,60.3 1 0
|
github.com/muety/wakapi/services/aggregation.go:59.50,61.3 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:63.60,67.3 3 0
|
github.com/muety/wakapi/services/aggregation.go:64.60,68.3 3 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:72.109,73.24 1 0
|
github.com/muety/wakapi/services/aggregation.go:73.109,74.24 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:73.24,74.111 1 0
|
github.com/muety/wakapi/services/aggregation.go:74.24,75.111 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:74.111,76.4 1 0
|
github.com/muety/wakapi/services/aggregation.go:75.111,77.4 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:76.9,79.4 2 0
|
github.com/muety/wakapi/services/aggregation.go:77.9,80.4 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:83.80,84.33 1 0
|
github.com/muety/wakapi/services/aggregation.go:84.80,85.33 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:84.33,85.60 1 0
|
github.com/muety/wakapi/services/aggregation.go:85.33,86.60 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:85.60,87.4 1 0
|
github.com/muety/wakapi/services/aggregation.go:86.60,88.4 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:91.100,95.59 3 0
|
github.com/muety/wakapi/services/aggregation.go:92.100,96.59 3 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:110.2,111.16 2 0
|
github.com/muety/wakapi/services/aggregation.go:111.2,112.16 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:117.2,118.16 2 0
|
github.com/muety/wakapi/services/aggregation.go:118.2,119.16 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:124.2,125.44 2 0
|
github.com/muety/wakapi/services/aggregation.go:125.2,126.44 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:130.2,130.41 1 0
|
github.com/muety/wakapi/services/aggregation.go:131.2,131.41 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:144.2,144.12 1 0
|
github.com/muety/wakapi/services/aggregation.go:145.2,145.12 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:95.59,98.3 2 0
|
github.com/muety/wakapi/services/aggregation.go:96.59,99.3 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:98.8,98.47 1 0
|
github.com/muety/wakapi/services/aggregation.go:99.8,99.47 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:98.47,100.30 2 0
|
github.com/muety/wakapi/services/aggregation.go:99.47,101.30 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:100.30,101.43 1 0
|
github.com/muety/wakapi/services/aggregation.go:101.30,102.43 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:101.43,103.5 1 0
|
github.com/muety/wakapi/services/aggregation.go:102.43,104.5 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:105.8,107.3 1 0
|
github.com/muety/wakapi/services/aggregation.go:106.8,108.3 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:111.16,114.3 2 0
|
github.com/muety/wakapi/services/aggregation.go:112.16,115.3 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:118.16,121.3 2 0
|
github.com/muety/wakapi/services/aggregation.go:119.16,122.3 2 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:125.44,127.3 1 0
|
github.com/muety/wakapi/services/aggregation.go:126.44,128.3 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:130.41,131.21 1 0
|
github.com/muety/wakapi/services/aggregation.go:131.41,132.21 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:131.21,135.4 1 0
|
github.com/muety/wakapi/services/aggregation.go:132.21,136.4 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:135.9,135.62 1 0
|
github.com/muety/wakapi/services/aggregation.go:136.9,136.62 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:135.62,139.4 1 0
|
github.com/muety/wakapi/services/aggregation.go:136.62,140.4 1 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:147.83,162.41 5 0
|
github.com/muety/wakapi/services/aggregation.go:148.83,163.41 5 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:162.41,172.3 3 0
|
github.com/muety/wakapi/services/aggregation.go:163.41,173.3 3 0
|
||||||
github.com/muety/wakapi/services/aggregation.go:175.34,178.2 2 0
|
github.com/muety/wakapi/services/aggregation.go:176.34,179.2 2 0
|
||||||
github.com/muety/wakapi/services/alias.go:16.77,21.2 1 1
|
github.com/muety/wakapi/services/alias.go:16.77,21.2 1 1
|
||||||
github.com/muety/wakapi/services/alias.go:25.63,27.16 2 1
|
github.com/muety/wakapi/services/alias.go:25.63,27.16 2 1
|
||||||
github.com/muety/wakapi/services/alias.go:30.2,30.12 1 1
|
github.com/muety/wakapi/services/alias.go:30.2,30.12 1 1
|
||||||
@ -404,7 +412,7 @@ github.com/muety/wakapi/services/language_mapping.go:55.109,57.16 2 0
|
|||||||
github.com/muety/wakapi/services/language_mapping.go:61.2,62.20 2 0
|
github.com/muety/wakapi/services/language_mapping.go:61.2,62.20 2 0
|
||||||
github.com/muety/wakapi/services/language_mapping.go:57.16,59.3 1 0
|
github.com/muety/wakapi/services/language_mapping.go:57.16,59.3 1 0
|
||||||
github.com/muety/wakapi/services/language_mapping.go:65.82,69.2 3 0
|
github.com/muety/wakapi/services/language_mapping.go:65.82,69.2 3 0
|
||||||
github.com/muety/wakapi/services/language_mapping.go:71.73,73.2 1 0
|
github.com/muety/wakapi/services/language_mapping.go:71.74,74.2 1 0
|
||||||
github.com/muety/wakapi/services/summary.go:27.149,35.2 1 1
|
github.com/muety/wakapi/services/summary.go:27.149,35.2 1 1
|
||||||
github.com/muety/wakapi/services/summary.go:39.120,42.52 2 1
|
github.com/muety/wakapi/services/summary.go:39.120,42.52 2 1
|
||||||
github.com/muety/wakapi/services/summary.go:47.2,47.44 1 1
|
github.com/muety/wakapi/services/summary.go:47.2,47.44 1 1
|
||||||
|
29
docs/advanced_setup.md
Normal file
29
docs/advanced_setup.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Advanced Setup
|
||||||
|
## Optional: Client-side proxy
|
||||||
|
Most Wakatime plugins work in a way that, for every heartbeat to send, the plugin calls your local [wakatime-cli](https://github.com/wakatime/wakatime) (a small Python program that is automatically installed when installing a Wakatime plugin) with a few command-line arguments, which is then run as a new process. Inside that process, a heartbeat request is forged and sent to the backend API – Wakapi in this case.
|
||||||
|
|
||||||
|
While this is convenient for plugin developers, as they do not have to deal with sending HTTP requests, etc., it comes with a minor drawback. Because the CLI process shuts down after each request, its TCP connection is closed as well. Accordingly, **TCP connections cannot be re-used** and every single heartbeat request is inevitably preceded by the `SYN` + `SYN ACK` + `ACK` sequence for establishing a new TCP connection as well as a handshake for establishing a new TLS session.
|
||||||
|
|
||||||
|
While this certainly does not hurt, it is still a bit of overhead. You can avoid that by setting up a local reverse proxy on your machine, that keeps running as a daemon and can therefore keep a continuous connection.
|
||||||
|
|
||||||
|
In this example, [Caddy](https://caddyserver.com) is used as an easy-to-set-up webserver / reverse proxy.
|
||||||
|
|
||||||
|
1. [Install Caddy](https://caddyserver.com/)
|
||||||
|
* When installing manually, don't forget to set up a systemd service to start Caddy on system startup
|
||||||
|
1. Create a Caddyfile
|
||||||
|
```
|
||||||
|
# /etc/caddy/Caddyfile
|
||||||
|
|
||||||
|
http://localhost:8070 {
|
||||||
|
reverse_proxy * {
|
||||||
|
to https://wakapi.dev # <-- substitute your own Wakapi host here
|
||||||
|
header_up Host {http.reverse_proxy.upstream.host}
|
||||||
|
header_down -Server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
1. Restart Caddy
|
||||||
|
1. Verify that you can access [`http://localhost:8070/api/health`](http://localhost:8070/api/health)
|
||||||
|
1. Update `~/.wakatime.cfg`
|
||||||
|
* Set `api_url = http://localhost:8070/api/heartbeat`
|
||||||
|
1. Done
|
73
main.go
73
main.go
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
"github.com/muety/wakapi/migrations/common"
|
"github.com/muety/wakapi/migrations/common"
|
||||||
@ -178,15 +179,71 @@ func main() {
|
|||||||
router.PathPrefix("/assets").Handler(http.FileServer(http.Dir("./static")))
|
router.PathPrefix("/assets").Handler(http.FileServer(http.Dir("./static")))
|
||||||
|
|
||||||
// Listen HTTP
|
// Listen HTTP
|
||||||
portString := config.Server.ListenIpV4 + ":" + strconv.Itoa(config.Server.Port)
|
listen(router)
|
||||||
s := &http.Server{
|
}
|
||||||
Handler: router,
|
|
||||||
Addr: portString,
|
func listen(handler http.Handler) {
|
||||||
ReadTimeout: 10 * time.Second,
|
var s4, s6 *http.Server
|
||||||
WriteTimeout: 10 * time.Second,
|
|
||||||
|
// IPv4
|
||||||
|
if config.Server.ListenIpV4 != "" {
|
||||||
|
bindString4 := config.Server.ListenIpV4 + ":" + strconv.Itoa(config.Server.Port)
|
||||||
|
s4 = &http.Server{
|
||||||
|
Handler: handler,
|
||||||
|
Addr: bindString4,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Listening on %+s\n", portString)
|
|
||||||
s.ListenAndServe()
|
// IPv6
|
||||||
|
if config.Server.ListenIpV6 != "" {
|
||||||
|
bindString6 := "[" + config.Server.ListenIpV6 + "]:" + strconv.Itoa(config.Server.Port)
|
||||||
|
s6 = &http.Server{
|
||||||
|
Handler: handler,
|
||||||
|
Addr: bindString6,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.UseTLS() {
|
||||||
|
if s4 != nil {
|
||||||
|
fmt.Printf("Listening for HTTPS on %s.\n", s4.Addr)
|
||||||
|
go func() {
|
||||||
|
if err := s4.ListenAndServeTLS(config.Server.TlsCertPath, config.Server.TlsKeyPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if s6 != nil {
|
||||||
|
fmt.Printf("Listening for HTTPS on %s.\n", s6.Addr)
|
||||||
|
go func() {
|
||||||
|
if err := s6.ListenAndServeTLS(config.Server.TlsCertPath, config.Server.TlsKeyPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if s4 != nil {
|
||||||
|
fmt.Printf("Listening for HTTP on %s.\n", s4.Addr)
|
||||||
|
go func() {
|
||||||
|
if err := s4.ListenAndServe(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
if s6 != nil {
|
||||||
|
fmt.Printf("Listening for HTTP on %s.\n", s6.Addr)
|
||||||
|
go func() {
|
||||||
|
if err := s6.ListenAndServe(); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<-make(chan interface{}, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDatabaseMigrations() {
|
func runDatabaseMigrations() {
|
||||||
|
@ -59,7 +59,7 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
vm := models.SummaryViewModel{
|
vm := models.SummaryViewModel{
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
LanguageColors: utils.FilterLanguageColors(h.config.App.LanguageColors, summary),
|
LanguageColors: utils.FilterLanguageColors(h.config.App.GetLanguageColors(), summary),
|
||||||
ApiKey: user.ApiKey,
|
ApiKey: user.ApiKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ func (srv *LanguageMappingService) Delete(mapping *models.LanguageMapping) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv LanguageMappingService) getServerMappings() map[string]string {
|
func (srv *LanguageMappingService) getServerMappings() map[string]string {
|
||||||
return srv.config.App.CustomLanguages
|
// https://dave.cheney.net/2017/04/30/if-a-map-isnt-a-reference-variable-what-is-it
|
||||||
|
return srv.config.App.GetCustomLanguages()
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f Summ
|
|||||||
|
|
||||||
func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User) (*models.Summary, error) {
|
func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User) (*models.Summary, error) {
|
||||||
// Check cache
|
// Check cache
|
||||||
cacheKey := srv.getHash(from.String(), to.String(), user.ID, "--aliased")
|
cacheKey := srv.getHash(from.String(), to.String(), user.ID)
|
||||||
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
if cacheResult, ok := srv.cache.Get(cacheKey); ok {
|
||||||
return cacheResult.(*models.Summary), nil
|
return cacheResult.(*models.Summary), nil
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
const SHOW_TOP_N = 10
|
|
||||||
const CHART_TARGET_SIZE = 200
|
const CHART_TARGET_SIZE = 200
|
||||||
|
|
||||||
const projectsCanvas = document.getElementById('chart-projects')
|
const projectsCanvas = document.getElementById('chart-projects')
|
||||||
@ -17,7 +16,16 @@ const containers = [projectContainer, osContainer, editorContainer, languageCont
|
|||||||
const canvases = [projectsCanvas, osCanvas, editorsCanvas, languagesCanvas, machinesCanvas]
|
const canvases = [projectsCanvas, osCanvas, editorsCanvas, languagesCanvas, machinesCanvas]
|
||||||
const data = [wakapiData.projects, wakapiData.operatingSystems, wakapiData.editors, wakapiData.languages, wakapiData.machines]
|
const data = [wakapiData.projects, wakapiData.operatingSystems, wakapiData.editors, wakapiData.languages, wakapiData.machines]
|
||||||
|
|
||||||
|
let topNPickers = [...document.getElementsByClassName('top-picker')]
|
||||||
|
topNPickers.sort(((a, b) => parseInt(a.attributes['data-entity'].value) - parseInt(b.attributes['data-entity'].value)))
|
||||||
|
topNPickers.forEach(e => {
|
||||||
|
const idx = parseInt(e.attributes['data-entity'].value)
|
||||||
|
e.max = Math.min(data[idx].length, 10)
|
||||||
|
e.value = e.max
|
||||||
|
})
|
||||||
|
|
||||||
let charts = []
|
let charts = []
|
||||||
|
let showTopN = []
|
||||||
let resizeCount = 0
|
let resizeCount = 0
|
||||||
|
|
||||||
String.prototype.toHHMMSS = function () {
|
String.prototype.toHHMMSS = function () {
|
||||||
@ -38,7 +46,7 @@ String.prototype.toHHMMSS = function () {
|
|||||||
return hours + ':' + minutes + ':' + seconds
|
return hours + ':' + minutes + ':' + seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw(subselection) {
|
||||||
function getTooltipOptions(key, type) {
|
function getTooltipOptions(key, type) {
|
||||||
return {
|
return {
|
||||||
mode: 'single',
|
mode: 'single',
|
||||||
@ -53,14 +61,20 @@ function draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
charts.forEach(c => c.destroy())
|
function shouldUpdate(index) {
|
||||||
|
return !subselection || (subselection.includes(index) && data[index].length >= showTopN[index])
|
||||||
|
}
|
||||||
|
|
||||||
let projectChart = !projectsCanvas.classList.contains('hidden')
|
charts
|
||||||
|
.filter((c, i) => shouldUpdate(i))
|
||||||
|
.forEach(c => c.destroy())
|
||||||
|
|
||||||
|
let projectChart = !projectsCanvas.classList.contains('hidden') && shouldUpdate(0)
|
||||||
? new Chart(projectsCanvas.getContext('2d'), {
|
? new Chart(projectsCanvas.getContext('2d'), {
|
||||||
type: 'horizontalBar',
|
type: 'horizontalBar',
|
||||||
data: {
|
data: {
|
||||||
datasets: wakapiData.projects
|
datasets: wakapiData.projects
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.projects.length))
|
.slice(0, Math.min(showTopN[0], wakapiData.projects.length))
|
||||||
.map(p => {
|
.map(p => {
|
||||||
return {
|
return {
|
||||||
label: p.key,
|
label: p.key,
|
||||||
@ -88,18 +102,18 @@ function draw() {
|
|||||||
})
|
})
|
||||||
: null
|
: null
|
||||||
|
|
||||||
let osChart = !osCanvas.classList.contains('hidden')
|
let osChart = !osCanvas.classList.contains('hidden') && shouldUpdate(1)
|
||||||
? new Chart(osCanvas.getContext('2d'), {
|
? new Chart(osCanvas.getContext('2d'), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: wakapiData.operatingSystems
|
data: wakapiData.operatingSystems
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length))
|
.slice(0, Math.min(showTopN[1], wakapiData.operatingSystems.length))
|
||||||
.map(p => parseInt(p.total)),
|
.map(p => parseInt(p.total)),
|
||||||
backgroundColor: wakapiData.operatingSystems.map(p => getRandomColor(p.key))
|
backgroundColor: wakapiData.operatingSystems.map(p => getRandomColor(p.key))
|
||||||
}],
|
}],
|
||||||
labels: wakapiData.operatingSystems
|
labels: wakapiData.operatingSystems
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length))
|
.slice(0, Math.min(showTopN[1], wakapiData.operatingSystems.length))
|
||||||
.map(p => p.key)
|
.map(p => p.key)
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@ -110,18 +124,18 @@ function draw() {
|
|||||||
})
|
})
|
||||||
: null
|
: null
|
||||||
|
|
||||||
let editorChart = !editorsCanvas.classList.contains('hidden')
|
let editorChart = !editorsCanvas.classList.contains('hidden') && shouldUpdate(2)
|
||||||
? new Chart(editorsCanvas.getContext('2d'), {
|
? new Chart(editorsCanvas.getContext('2d'), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: wakapiData.editors
|
data: wakapiData.editors
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length))
|
.slice(0, Math.min(showTopN[2], wakapiData.editors.length))
|
||||||
.map(p => parseInt(p.total)),
|
.map(p => parseInt(p.total)),
|
||||||
backgroundColor: wakapiData.editors.map(p => getRandomColor(p.key))
|
backgroundColor: wakapiData.editors.map(p => getRandomColor(p.key))
|
||||||
}],
|
}],
|
||||||
labels: wakapiData.editors
|
labels: wakapiData.editors
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length))
|
.slice(0, Math.min(showTopN[2], wakapiData.editors.length))
|
||||||
.map(p => p.key)
|
.map(p => p.key)
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@ -132,18 +146,18 @@ function draw() {
|
|||||||
})
|
})
|
||||||
: null
|
: null
|
||||||
|
|
||||||
let languageChart = !languagesCanvas.classList.contains('hidden')
|
let languageChart = !languagesCanvas.classList.contains('hidden') && shouldUpdate(3)
|
||||||
? new Chart(languagesCanvas.getContext('2d'), {
|
? new Chart(languagesCanvas.getContext('2d'), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: wakapiData.languages
|
data: wakapiData.languages
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
|
.slice(0, Math.min(showTopN[3], wakapiData.languages.length))
|
||||||
.map(p => parseInt(p.total)),
|
.map(p => parseInt(p.total)),
|
||||||
backgroundColor: wakapiData.languages.map(p => languageColors[p.key.toLowerCase()] || getRandomColor(p.key))
|
backgroundColor: wakapiData.languages.map(p => languageColors[p.key.toLowerCase()] || getRandomColor(p.key))
|
||||||
}],
|
}],
|
||||||
labels: wakapiData.languages
|
labels: wakapiData.languages
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
|
.slice(0, Math.min(showTopN[3], wakapiData.languages.length))
|
||||||
.map(p => p.key)
|
.map(p => p.key)
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@ -154,18 +168,18 @@ function draw() {
|
|||||||
})
|
})
|
||||||
: null
|
: null
|
||||||
|
|
||||||
let machineChart = !machinesCanvas.classList.contains('hidden')
|
let machineChart = !machinesCanvas.classList.contains('hidden') && shouldUpdate(4)
|
||||||
? new Chart(machinesCanvas.getContext('2d'), {
|
? new Chart(machinesCanvas.getContext('2d'), {
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
data: {
|
data: {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: wakapiData.machines
|
data: wakapiData.machines
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
|
.slice(0, Math.min(showTopN[4], wakapiData.machines.length))
|
||||||
.map(p => parseInt(p.total)),
|
.map(p => parseInt(p.total)),
|
||||||
backgroundColor: wakapiData.machines.map(p => getRandomColor(p.key))
|
backgroundColor: wakapiData.machines.map(p => getRandomColor(p.key))
|
||||||
}],
|
}],
|
||||||
labels: wakapiData.machines
|
labels: wakapiData.machines
|
||||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
|
.slice(0, Math.min(showTopN[4], wakapiData.machines.length))
|
||||||
.map(p => p.key)
|
.map(p => p.key)
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@ -180,13 +194,14 @@ function draw() {
|
|||||||
|
|
||||||
charts = [projectChart, osChart, editorChart, languageChart, machineChart].filter(c => !!c)
|
charts = [projectChart, osChart, editorChart, languageChart, machineChart].filter(c => !!c)
|
||||||
|
|
||||||
charts.forEach(c => c.options.onResize(c.chart))
|
if (!subselection) {
|
||||||
equalizeHeights()
|
charts.forEach(c => c.options.onResize(c.chart))
|
||||||
|
equalizeHeights()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTopLabels() {
|
function parseTopN() {
|
||||||
[...document.getElementsByClassName('top-label')]
|
showTopN = topNPickers.map(e => parseInt(e.value))
|
||||||
.forEach(e => e.innerText = `(top ${SHOW_TOP_N})`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePlaceholders(mask) {
|
function togglePlaceholders(mask) {
|
||||||
@ -301,7 +316,12 @@ window.addEventListener('click', function (event) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
setTopLabels()
|
topNPickers.forEach(e => e.addEventListener('change', () => {
|
||||||
|
parseTopN()
|
||||||
|
draw([parseInt(e.attributes['data-entity'].value)])
|
||||||
|
}))
|
||||||
|
|
||||||
|
parseTopN()
|
||||||
togglePlaceholders(getPresentDataMask())
|
togglePlaceholders(getPresentDataMask())
|
||||||
draw()
|
draw()
|
||||||
})
|
})
|
||||||
|
@ -1 +1 @@
|
|||||||
1.17.3
|
1.18.1
|
||||||
|
@ -66,9 +66,13 @@
|
|||||||
<div class="flex flex-wrap justify-center">
|
<div class="flex flex-wrap justify-center">
|
||||||
<div class="w-full lg:w-1/2 p-1">
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="project-container" style="height: 300px">
|
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="project-container" style="height: 300px">
|
||||||
<div class="self-center flex">
|
<div class="flex justify-between">
|
||||||
<span class="font-semibold mr-1">Projects</span>
|
<div class="w-1/4 flex-1"></div>
|
||||||
<span id="project-top-label" class="top-label"></span>
|
<span class="font-semibold w-1/2 text-center flex-1">Projects</span>
|
||||||
|
<div class="flex justify-end flex-1 text-xs items-center">
|
||||||
|
<label for="project-top-picker" class="mr-1">Show: </label>
|
||||||
|
<input type="number" min="1" id="project-top-picker" data-entity="0" class="w-1/4 top-picker bg-gray-200 rounded-md text-center" value="10">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="chart-projects"></canvas>
|
<canvas id="chart-projects"></canvas>
|
||||||
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
||||||
@ -79,9 +83,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-1/2 p-1">
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="os-container" style="height: 300px">
|
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="os-container" style="height: 300px">
|
||||||
<div class="self-center flex">
|
<div class="flex justify-between">
|
||||||
<span class="font-semibold mr-1">Operating Systems</span>
|
<div class="w-1/4 flex-1"></div>
|
||||||
<span id="os-top-label" class="top-label"></span>
|
<span class="font-semibold w-1/2 text-center flex-1">Operating Systems</span>
|
||||||
|
<div class="flex justify-end flex-1 text-xs items-center">
|
||||||
|
<label for="os-top-picker" class="mr-1">Show: </label>
|
||||||
|
<input type="number" min="1" id="os-top-picker" data-entity="1" class="w-1/4 top-picker bg-gray-200 rounded-md text-center" value="10">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="chart-os"></canvas>
|
<canvas id="chart-os"></canvas>
|
||||||
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
||||||
@ -92,9 +100,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-1/2 p-1">
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col relative" id="language-container" style="height: 300px">
|
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col relative" id="language-container" style="height: 300px">
|
||||||
<div class="self-center flex">
|
<div class="flex justify-between">
|
||||||
<span class="font-semibold mr-1">Languages</span>
|
<div class="w-1/4 flex-1"></div>
|
||||||
<span id="language-top-label" class="top-label"></span>
|
<span class="font-semibold w-1/2 text-center flex-1">Languages</span>
|
||||||
|
<div class="flex justify-end flex-1 text-xs items-center">
|
||||||
|
<label for="language-top-picker" class="mr-1">Show: </label>
|
||||||
|
<input type="number" min="1" id="language-top-picker" data-entity="3" class="w-1/4 top-picker bg-gray-200 rounded-md text-center" value="10">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="chart-language"></canvas>
|
<canvas id="chart-language"></canvas>
|
||||||
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
||||||
@ -105,9 +117,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-1/2 p-1">
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="editor-container" style="height: 300px">
|
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="editor-container" style="height: 300px">
|
||||||
<div class="self-center flex">
|
<div class="flex justify-between">
|
||||||
<span class="font-semibold mr-1">Editors</span>
|
<div class="w-1/4 flex-1"></div>
|
||||||
<span id="editor-top-label" class="top-label"></span>
|
<span class="font-semibold w-1/2 text-center flex-1">Editors</span>
|
||||||
|
<div class="flex justify-end flex-1 text-xs items-center">
|
||||||
|
<label for="editor-top-picker" class="mr-1">Show: </label>
|
||||||
|
<input type="number" min="1" id="editor-top-picker" data-entity="2" class="w-1/4 top-picker bg-gray-200 rounded-md text-center" value="10">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="chart-editor"></canvas>
|
<canvas id="chart-editor"></canvas>
|
||||||
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
||||||
@ -118,9 +134,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-1/2 p-1">
|
<div class="w-full lg:w-1/2 p-1">
|
||||||
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="machine-container" style="height: 300px">
|
<div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="machine-container" style="height: 300px">
|
||||||
<div class="self-center flex">
|
<div class="flex justify-between">
|
||||||
<span class="font-semibold mr-1">Machines</span>
|
<div class="w-1/4 flex-1"></div>
|
||||||
<span id="machine-top-label" class="top-label"></span>
|
<span class="font-semibold w-1/2 text-center flex-1">Machines</span>
|
||||||
|
<div class="flex justify-end flex-1 text-xs items-center">
|
||||||
|
<label for="machine-top-picker" class="mr-1">Show: </label>
|
||||||
|
<input type="number" min="1" id="machine-top-picker" data-entity="4" class="w-1/4 top-picker bg-gray-200 rounded-md text-center" value="10">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="chart-machine"></canvas>
|
<canvas id="chart-machine"></canvas>
|
||||||
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
|
||||||
|
Reference in New Issue
Block a user