mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
cec2a84e2d | |||
ffb0b84d78 | |||
8a7333b899 | |||
dd3b9c9b9c | |||
d2b62e21c5 | |||
9505773165 | |||
4bfc8a9e9f | |||
df5fe6e623 | |||
037ad7b9b1 | |||
ec10cc922c | |||
acb76e1ab1 | |||
252a304ba8 | |||
c863cf6dc5 | |||
373d969734 | |||
99a3e8f5da | |||
4302cfcbd6 | |||
7cca0055fe | |||
20993a1182 | |||
d5a85639b1 |
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@ -11,6 +11,15 @@ jobs:
|
||||
name: 'Build and publish Docker image'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set version
|
||||
run: |
|
||||
(git describe --tags --exact-match \
|
||||
|| git symbolic-ref -q --short HEAD \
|
||||
|| git rev-parse --short HEAD) > version.txt 2> /dev/null
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
@ -47,6 +56,7 @@ jobs:
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
|
44
.github/workflows/release.yml
vendored
44
.github/workflows/release.yml
vendored
@ -8,20 +8,13 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
name: 'Build, package and release to GitHub'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
include:
|
||||
- platform: ubuntu-latest
|
||||
alias: linux
|
||||
- platform: macos-latest
|
||||
alias: mac
|
||||
- platform: windows-latest
|
||||
alias: win
|
||||
GOOS: [darwin, windows, linux]
|
||||
GOARCH: [amd64, arm64]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
@ -33,24 +26,29 @@ jobs:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: go get
|
||||
- name: Set version
|
||||
shell: bash
|
||||
run: |
|
||||
(git describe --tags --exact-match \
|
||||
|| git symbolic-ref -q --short HEAD \
|
||||
|| git rev-parse --short HEAD) > version.txt 2> /dev/null
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
mkdir -p dist/ && cd dist/
|
||||
cp ../config.default.yml config.yml
|
||||
|
||||
- name: Build
|
||||
run: go build -v .
|
||||
working-directory: ./dist
|
||||
run: |
|
||||
GOOS=${{ matrix.GOOS }} GOARCH=${{ matrix.GOARCH }} go build -v ../
|
||||
|
||||
- name: Compress working folder on Windows
|
||||
if: runner.os == 'Windows'
|
||||
- name: Compress working folder
|
||||
working-directory: ./dist
|
||||
run: |
|
||||
cp .\config.default.yml .\config.yml
|
||||
Compress-Archive -Path .\wakapi.exe, .\config.yml -DestinationPath wakapi_${{ matrix.alias }}_amd64.zip
|
||||
- name: Compress working folder on Unix
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
cp config.default.yml config.yml
|
||||
zip -9 wakapi_${{ matrix.alias }}_amd64.zip wakapi config.yml
|
||||
zip -9 wakapi_${{ matrix.GOOS }}_${{ matrix.GOARCH }}.zip *
|
||||
|
||||
- name: Upload built executable to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: wakapi_${{ matrix.alias }}_amd64.zip
|
||||
files: ./dist/*.zip
|
||||
|
60
Dockerfile
60
Dockerfile
@ -1,33 +1,25 @@
|
||||
# To build locally: docker buildx build . -t wakapi --load
|
||||
|
||||
# Preparation to save some time
|
||||
FROM --platform=$BUILDPLATFORM golang:1.18-alpine AS prep-env
|
||||
WORKDIR /src
|
||||
|
||||
ADD ./go.mod .
|
||||
RUN go mod download
|
||||
ADD . .
|
||||
|
||||
RUN wget "https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh" -O wait-for-it.sh && \
|
||||
chmod +x wait-for-it.sh
|
||||
|
||||
# Build Stage
|
||||
FROM golang:1.18-alpine AS build-env
|
||||
WORKDIR /src
|
||||
|
||||
# Required for go-sqlite3
|
||||
RUN apk add --no-cache gcc musl-dev
|
||||
|
||||
WORKDIR /src
|
||||
COPY --from=prep-env /src .
|
||||
RUN wget "https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh" -O wait-for-it.sh && \
|
||||
chmod +x wait-for-it.sh
|
||||
|
||||
RUN go build -v -o wakapi
|
||||
ADD ./go.mod ./go.sum ./
|
||||
RUN go mod download
|
||||
ADD . .
|
||||
|
||||
WORKDIR /app
|
||||
RUN cp /src/wakapi . && \
|
||||
cp /src/config.default.yml config.yml && \
|
||||
sed -i 's/listen_ipv6: ::1/listen_ipv6: /g' config.yml && \
|
||||
cp /src/wait-for-it.sh . && \
|
||||
cp /src/entrypoint.sh .
|
||||
RUN go build -ldflags "-s -w" -v -o wakapi main.go
|
||||
|
||||
WORKDIR /staging
|
||||
RUN mkdir ./data ./app && \
|
||||
cp /src/wakapi app/ && \
|
||||
cp /src/config.default.yml app/config.yml && \
|
||||
sed -i 's/listen_ipv6: ::1/listen_ipv6: /g' app/config.yml && \
|
||||
cp /src/wait-for-it.sh app/ && \
|
||||
cp /src/entrypoint.sh app/
|
||||
|
||||
# Run Stage
|
||||
|
||||
@ -41,18 +33,18 @@ WORKDIR /app
|
||||
RUN apk add --no-cache bash ca-certificates tzdata
|
||||
|
||||
# See README.md and config.default.yml for all config options
|
||||
ENV ENVIRONMENT prod
|
||||
ENV WAKAPI_DB_TYPE sqlite3
|
||||
ENV WAKAPI_DB_USER ''
|
||||
ENV WAKAPI_DB_PASSWORD ''
|
||||
ENV WAKAPI_DB_HOST ''
|
||||
ENV WAKAPI_DB_NAME=/data/wakapi.db
|
||||
ENV WAKAPI_PASSWORD_SALT ''
|
||||
ENV WAKAPI_LISTEN_IPV4 '0.0.0.0'
|
||||
ENV WAKAPI_INSECURE_COOKIES 'true'
|
||||
ENV WAKAPI_ALLOW_SIGNUP 'true'
|
||||
ENV ENVIRONMENT=prod \
|
||||
WAKAPI_DB_TYPE=sqlite3 \
|
||||
WAKAPI_DB_USER='' \
|
||||
WAKAPI_DB_PASSWORD='' \
|
||||
WAKAPI_DB_HOST='' \
|
||||
WAKAPI_DB_NAME=/data/wakapi.db \
|
||||
WAKAPI_PASSWORD_SALT='' \
|
||||
WAKAPI_LISTEN_IPV4='0.0.0.0' \
|
||||
WAKAPI_INSECURE_COOKIES='true' \
|
||||
WAKAPI_ALLOW_SIGNUP='true'
|
||||
|
||||
COPY --from=build-env /app .
|
||||
COPY --from=build-env /staging /
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
|
@ -4,10 +4,10 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"github.com/jinzhu/configor"
|
||||
"github.com/muety/wakapi/data"
|
||||
"github.com/muety/wakapi/models"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
@ -29,6 +30,7 @@ const (
|
||||
KeyLatestTotalTime = "latest_total_time"
|
||||
KeyLatestTotalUsers = "latest_total_users"
|
||||
KeyLastImportImport = "last_import"
|
||||
KeyNewsbox = "newsbox"
|
||||
|
||||
SimpleDateFormat = "2006-01-02"
|
||||
SimpleDateTimeFormat = "2006-01-02 15:04:05"
|
||||
@ -363,7 +365,13 @@ func Load(version string) *Config {
|
||||
}
|
||||
|
||||
env = config.Env
|
||||
|
||||
config.Version = strings.TrimSpace(version)
|
||||
tagVersionMatch, _ := regexp.MatchString(`\d+\.\d+\.\d+`, version)
|
||||
if tagVersionMatch {
|
||||
config.Version = "v" + config.Version
|
||||
}
|
||||
|
||||
config.InstanceId = uuid.NewV4().String()
|
||||
config.App.Colors = readColors()
|
||||
config.Db.Dialect = resolveDbDialect(config.Db.Type)
|
||||
|
26
main.go
26
main.go
@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/muety/wakapi/migrations"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net"
|
||||
@ -11,28 +10,29 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/lpar/gzipped/v2"
|
||||
"github.com/muety/wakapi/routes/relay"
|
||||
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/gorilla/handlers"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/repositories"
|
||||
"github.com/muety/wakapi/routes/api"
|
||||
"github.com/muety/wakapi/services/mail"
|
||||
fsutils "github.com/muety/wakapi/utils/fs"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/lpar/gzipped/v2"
|
||||
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
"github.com/muety/wakapi/migrations"
|
||||
"github.com/muety/wakapi/repositories"
|
||||
"github.com/muety/wakapi/routes"
|
||||
"github.com/muety/wakapi/routes/api"
|
||||
shieldsV1Routes "github.com/muety/wakapi/routes/compat/shields/v1"
|
||||
wtV1Routes "github.com/muety/wakapi/routes/compat/wakatime/v1"
|
||||
"github.com/muety/wakapi/routes/relay"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/services/mail"
|
||||
fsutils "github.com/muety/wakapi/utils/fs"
|
||||
|
||||
_ "gorm.io/driver/mysql"
|
||||
_ "gorm.io/driver/postgres"
|
||||
_ "gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
// Embed version.txt
|
||||
@ -121,6 +121,10 @@ func main() {
|
||||
// Connect to database
|
||||
var err error
|
||||
db, err = gorm.Open(config.Db.GetDialector(), &gorm.Config{Logger: gormLogger})
|
||||
if err != nil {
|
||||
logbuch.Error(err.Error())
|
||||
logbuch.Fatal("could not open database")
|
||||
}
|
||||
if config.Db.IsSQLite() {
|
||||
db.Exec("PRAGMA foreign_keys = ON;")
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ var (
|
||||
IntervalPast7DaysYesterday = &IntervalKey{"Last 7 Days from Yesterday"}
|
||||
IntervalPast14Days = &IntervalKey{"Last 14 Days"}
|
||||
IntervalPast30Days = &IntervalKey{"30_days", "last_30_days", "Last 30 Days"}
|
||||
IntervalPast12Months = &IntervalKey{"12_months", "last_12_months"}
|
||||
IntervalAny = &IntervalKey{"any"}
|
||||
IntervalPast6Months = &IntervalKey{"6_months", "last_6_months"}
|
||||
IntervalPast12Months = &IntervalKey{"12_months", "last_12_months", "last_year"}
|
||||
IntervalAny = &IntervalKey{"any", "all_time"}
|
||||
)
|
||||
|
||||
var AllIntervals = []*IntervalKey{
|
||||
@ -30,6 +31,7 @@ var AllIntervals = []*IntervalKey{
|
||||
IntervalPast7DaysYesterday,
|
||||
IntervalPast14Days,
|
||||
IntervalPast30Days,
|
||||
IntervalPast6Months,
|
||||
IntervalPast12Months,
|
||||
IntervalAny,
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
package view
|
||||
|
||||
type Newsbox struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type HomeViewModel struct {
|
||||
Success string
|
||||
Error string
|
||||
TotalHours int
|
||||
TotalUsers int
|
||||
Newsbox *Newsbox
|
||||
}
|
||||
|
||||
func (s *HomeViewModel) WithSuccess(m string) *HomeViewModel {
|
||||
|
@ -109,7 +109,7 @@ func (r *SummaryRepository) populateItems(summaries []*models.Summary, condition
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if _, ok := summaryMap[item.SummaryID]; ok {
|
||||
if _, ok := summaryMap[item.SummaryID]; !ok {
|
||||
continue
|
||||
}
|
||||
l := summaryMap[item.SummaryID][0].ItemsByType(item.Type)
|
||||
|
@ -79,6 +79,12 @@ func (h *HeartbeatApiHandler) Post(w http.ResponseWriter, r *http.Request) {
|
||||
machineName := r.Header.Get("X-Machine-Name")
|
||||
|
||||
for _, hb := range heartbeats {
|
||||
if hb == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("invalid heartbeat object"))
|
||||
return
|
||||
}
|
||||
|
||||
hb.OperatingSystem = opSys
|
||||
hb.Editor = editor
|
||||
hb.Machine = machineName
|
||||
|
@ -37,7 +37,7 @@ func (h *SummaryApiHandler) RegisterRoutes(router *mux.Router) {
|
||||
// @ID get-summary
|
||||
// @Tags summary
|
||||
// @Produce json
|
||||
// @Param interval query string false "Interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 12_months, last_12_months, any)
|
||||
// @Param interval query string false "Interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 6_months, last_6_months, 12_months, last_12_months, last_year, any, all_time)
|
||||
// @Param from query string false "Start date (e.g. '2021-02-07')"
|
||||
// @Param to query string false "End date (e.g. '2021-02-08')"
|
||||
// @Param recompute query bool false "Whether to recompute the summary from raw heartbeat or use cache"
|
||||
|
@ -43,7 +43,7 @@ func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
|
||||
// @Tags badges
|
||||
// @Produce json
|
||||
// @Param user path string true "User ID to fetch data for"
|
||||
// @Param interval path string true "Interval to aggregate data for" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 12_months, last_12_months, any)
|
||||
// @Param interval path string true "Interval to aggregate data for" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 6_months, last_6_months, 12_months, last_12_months, last_year, any, all_time)
|
||||
// @Param filter path string true "Filter to apply (e.g. 'project:wakapi' or 'language:Go')"
|
||||
// @Success 200 {object} v1.BadgeData
|
||||
// @Router /compat/shields/v1/{user}/{interval}/{filter} [get]
|
||||
|
@ -48,7 +48,7 @@ func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
|
||||
// @Tags wakatime
|
||||
// @Produce json
|
||||
// @Param user path string true "User ID to fetch data for (or 'current')"
|
||||
// @Param range path string false "Range interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 12_months, last_12_months, any)
|
||||
// @Param range path string false "Range interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 6_months, last_6_months, 12_months, last_12_months, last_year, any, all_time)
|
||||
// @Param project query string false "Project to filter by"
|
||||
// @Param language query string false "Language to filter by"
|
||||
// @Param editor query string false "Editor to filter by"
|
||||
|
@ -50,7 +50,7 @@ func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {
|
||||
// @Tags wakatime
|
||||
// @Produce json
|
||||
// @Param user path string true "User ID to fetch data for (or 'current')"
|
||||
// @Param range query string false "Range interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 12_months, last_12_months, any)
|
||||
// @Param range query string false "Range interval identifier" Enums(today, yesterday, week, month, year, 7_days, last_7_days, 30_days, last_30_days, 6_months, last_6_months, 12_months, last_12_months, last_year, any, all_time)
|
||||
// @Param start query string false "Start date (e.g. '2021-02-07')"
|
||||
// @Param end query string false "End date (e.g. '2021-02-08')"
|
||||
// @Param project query string false "Project to filter by"
|
||||
|
@ -1,6 +1,7 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/schema"
|
||||
@ -10,6 +11,7 @@ import (
|
||||
"github.com/muety/wakapi/services"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -49,23 +51,29 @@ func (h *HomeHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *HomeHandler) buildViewModel(r *http.Request) *view.HomeViewModel {
|
||||
var totalHours int
|
||||
var totalUsers int
|
||||
var newsbox view.Newsbox
|
||||
|
||||
if t, err := h.keyValueSrvc.GetString(conf.KeyLatestTotalTime); err == nil && t != nil && t.Value != "" {
|
||||
if d, err := time.ParseDuration(t.Value); err == nil {
|
||||
if kv, err := h.keyValueSrvc.GetString(conf.KeyLatestTotalTime); err == nil && kv != nil && kv.Value != "" {
|
||||
if d, err := time.ParseDuration(kv.Value); err == nil {
|
||||
totalHours = int(d.Hours())
|
||||
}
|
||||
}
|
||||
|
||||
if t, err := h.keyValueSrvc.GetString(conf.KeyLatestTotalUsers); err == nil && t != nil && t.Value != "" {
|
||||
if d, err := strconv.Atoi(t.Value); err == nil {
|
||||
if kv, err := h.keyValueSrvc.GetString(conf.KeyLatestTotalUsers); err == nil && kv != nil && kv.Value != "" {
|
||||
if d, err := strconv.Atoi(kv.Value); err == nil {
|
||||
totalUsers = d
|
||||
}
|
||||
}
|
||||
|
||||
if kv, err := h.keyValueSrvc.GetString(conf.KeyNewsbox); err == nil && kv != nil && kv.Value != "" {
|
||||
json.NewDecoder(strings.NewReader(kv.Value)).Decode(&newsbox)
|
||||
}
|
||||
|
||||
return &view.HomeViewModel{
|
||||
Success: r.URL.Query().Get("success"),
|
||||
Error: r.URL.Query().Get("error"),
|
||||
TotalHours: totalHours,
|
||||
TotalUsers: totalUsers,
|
||||
Newsbox: &newsbox,
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,15 @@ package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
"github.com/muety/wakapi/views"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"github.com/muety/wakapi/views"
|
||||
)
|
||||
|
||||
type action func(w http.ResponseWriter, r *http.Request) (int, string, string)
|
||||
|
@ -93,6 +93,22 @@ body {
|
||||
@apply font-semibold text-gray-400 hover:text-gray-300;
|
||||
}
|
||||
|
||||
.newsbox {
|
||||
@apply px-4 py-2 border-2 border-red-700 bg-gray-850 rounded-md text-white border-green-700;
|
||||
}
|
||||
|
||||
.newsbox-default {
|
||||
@apply border-green-700;
|
||||
}
|
||||
|
||||
.newsbox-warning {
|
||||
@apply border-yellow-600;
|
||||
}
|
||||
|
||||
.newsbox-danger {
|
||||
@apply border-red-700;
|
||||
}
|
||||
|
||||
::-webkit-calendar-picker-indicator {
|
||||
filter: invert(1);
|
||||
cursor: pointer;
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -54,9 +54,13 @@ const docTemplate = `{
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Interval to aggregate data for",
|
||||
@ -354,9 +358,13 @@ const docTemplate = `{
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Range interval identifier",
|
||||
@ -445,9 +453,13 @@ const docTemplate = `{
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Range interval identifier",
|
||||
@ -809,9 +821,13 @@ const docTemplate = `{
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Interval identifier",
|
||||
|
@ -46,9 +46,13 @@
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Interval to aggregate data for",
|
||||
@ -346,9 +350,13 @@
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Range interval identifier",
|
||||
@ -437,9 +445,13 @@
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Range interval identifier",
|
||||
@ -801,9 +813,13 @@
|
||||
"last_7_days",
|
||||
"30_days",
|
||||
"last_30_days",
|
||||
"6_months",
|
||||
"last_6_months",
|
||||
"12_months",
|
||||
"last_12_months",
|
||||
"any"
|
||||
"last_year",
|
||||
"any",
|
||||
"all_time"
|
||||
],
|
||||
"type": "string",
|
||||
"description": "Interval identifier",
|
||||
|
@ -430,9 +430,13 @@ paths:
|
||||
- last_7_days
|
||||
- 30_days
|
||||
- last_30_days
|
||||
- 6_months
|
||||
- last_6_months
|
||||
- 12_months
|
||||
- last_12_months
|
||||
- last_year
|
||||
- any
|
||||
- all_time
|
||||
in: path
|
||||
name: interval
|
||||
required: true
|
||||
@ -623,9 +627,13 @@ paths:
|
||||
- last_7_days
|
||||
- 30_days
|
||||
- last_30_days
|
||||
- 6_months
|
||||
- last_6_months
|
||||
- 12_months
|
||||
- last_12_months
|
||||
- last_year
|
||||
- any
|
||||
- all_time
|
||||
in: path
|
||||
name: range
|
||||
type: string
|
||||
@ -686,9 +694,13 @@ paths:
|
||||
- last_7_days
|
||||
- 30_days
|
||||
- last_30_days
|
||||
- 6_months
|
||||
- last_6_months
|
||||
- 12_months
|
||||
- last_12_months
|
||||
- last_year
|
||||
- any
|
||||
- all_time
|
||||
in: query
|
||||
name: range
|
||||
type: string
|
||||
@ -925,9 +937,13 @@ paths:
|
||||
- last_7_days
|
||||
- 30_days
|
||||
- last_30_days
|
||||
- 6_months
|
||||
- last_6_months
|
||||
- 12_months
|
||||
- last_12_months
|
||||
- last_year
|
||||
- any
|
||||
- all_time
|
||||
in: query
|
||||
name: interval
|
||||
type: string
|
||||
|
@ -2,6 +2,11 @@ module.exports = {
|
||||
purge: {
|
||||
enabled: true,
|
||||
mode: 'all',
|
||||
content: ['./views/*.tpl.html']
|
||||
}
|
||||
content: ['./views/*.tpl.html'],
|
||||
safelist: [
|
||||
'newsbox-default',
|
||||
'newsbox-warning',
|
||||
'newsbox-danger',
|
||||
]
|
||||
},
|
||||
}
|
@ -60,6 +60,8 @@ func ResolveIntervalTZ(interval *models.IntervalKey, tz *time.Location) (err err
|
||||
from = now.AddDate(0, 0, -14)
|
||||
case models.IntervalPast30Days:
|
||||
from = now.AddDate(0, 0, -30)
|
||||
case models.IntervalPast6Months:
|
||||
from = now.AddDate(0, -6, 0)
|
||||
case models.IntervalPast12Months:
|
||||
from = now.AddDate(0, -12, 0)
|
||||
case models.IntervalAny:
|
||||
|
@ -1 +1 @@
|
||||
2.3.5
|
||||
dev
|
||||
|
@ -1,6 +1,6 @@
|
||||
<footer class="flex justify-between w-full text-center text-gray-500 text-xs mt-20">
|
||||
<div class="text-xs font-mono font-semibold">
|
||||
v{{ getVersion }} @ {{ getDbType }}
|
||||
{{ getVersion }} @ {{ getDbType }}
|
||||
</div>
|
||||
<div class="font-semibold text-sm hidden sm:inline-block">
|
||||
Made with <span class="iconify inline" data-icon="bi:heart-fill"></span> by <a href="https://muetsch.io" class="text-gray-400 hover:text-gray-300">Ferdinand Mütsch</a> as <a
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
{{ template "alerts.tpl.html" . }}
|
||||
|
||||
<div class="absolute flex top-0 right-0 mr-8 mt-10 py-2">
|
||||
<div class="absolute flex top-0 right-0 mr-4 mt-10 py-2">
|
||||
<div class="mx-1">
|
||||
<a href="login" class="btn-primary">
|
||||
<span class="iconify inline" data-icon="fluent:key-24-filled"></span> Login</a>
|
||||
@ -18,6 +18,12 @@
|
||||
|
||||
<main class="mt-10 px-4 md:px-10 lg:px-24 flex-grow flex justify-center w-full">
|
||||
<div class="flex flex-col text-white">
|
||||
{{ if and .Newsbox .Newsbox.Text }}
|
||||
<div class="mb-14 -mt-4 newsbox newsbox-{{ .Newsbox.Type }}">
|
||||
{{ .Newsbox.Text | htmlSafe }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<h1 class="text-8xl font-semibold antialiased text-center mb-10 leading-snug">Keep Track of<br><span
|
||||
class="text-green-700">Your</span> Coding Time</h1>
|
||||
<p class="text-center text-gray-500 text-xl my-2">Wakapi is an open-source tool that helps you keep track of the
|
||||
|
@ -14,6 +14,7 @@
|
||||
<a id="time-option-year" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('year')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">This Year</a>
|
||||
<a id="time-option-last_7_days" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('last_7_days')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">Past 7 Days</a>
|
||||
<a id="time-option-last_30_days" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('last_30_days')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">Past 30 Days</a>
|
||||
<a id="time-option-last_6_months" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('last_6_months')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">Past 6 Months</a>
|
||||
<a id="time-option-last_12_months" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('last_12_months')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">Past 12 Months</a>
|
||||
<a id="time-option-any" class="submenu-item hover:bg-gray-800 rounded p-1 text-right w-full text-gray-300 px-2 font-semibold text-sm" :href="intervalLink('any')" @click="state.showDropdownTimepicker = !state.showDropdownTimepicker" data-trigger-for="showDropdownTimepicker">All Time</a>
|
||||
<hr class="my-2">
|
||||
|
Reference in New Issue
Block a user