mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-13 00:03:31 -04:00
Compare commits
11 Commits
e64c2faf85
...
50bd7d0b24
Author | SHA1 | Date | |
---|---|---|---|
|
50bd7d0b24 | ||
|
28a89e360f | ||
|
4c81dae297 | ||
|
0c79a655d4 | ||
|
1ea5c8b0ff | ||
|
3dd3b1b456 | ||
|
1b115296d3 | ||
|
faae819f5d | ||
|
ee99cf6313 | ||
|
32185efc14 | ||
|
d783384c19 |
@ -76,7 +76,6 @@ cpu.out
|
||||
/yarn-error.log
|
||||
/npm-debug.log*
|
||||
/public/js
|
||||
/public/serviceworker.js
|
||||
/public/css
|
||||
/public/fonts
|
||||
/public/img/webpack
|
||||
|
15
.github/file-filters.yml
vendored
15
.github/file-filters.yml
vendored
@ -1,15 +0,0 @@
|
||||
docs: &docs
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
|
||||
backend: &backend
|
||||
- "**/*.go"
|
||||
- "**/*.tmpl"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
|
||||
frontend: &frontend
|
||||
- "**/*.js"
|
||||
- "web_src/**"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
43
.github/workflows/files-changed.yml
vendored
43
.github/workflows/files-changed.yml
vendored
@ -1,32 +1,53 @@
|
||||
name: files changed
|
||||
name: files-changed
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
outputs:
|
||||
docs:
|
||||
description: "whether docs files changed"
|
||||
value: ${{ jobs.files-changed.outputs.docs }}
|
||||
backend:
|
||||
description: "whether backend files changed"
|
||||
value: ${{ jobs.files-changed.outputs.backend }}
|
||||
value: ${{ jobs.detect.outputs.backend }}
|
||||
frontend:
|
||||
description: "whether frontend files changed"
|
||||
value: ${{ jobs.files-changed.outputs.frontend }}
|
||||
value: ${{ jobs.detect.outputs.frontend }}
|
||||
docs:
|
||||
description: "whether docs files changed"
|
||||
value: ${{ jobs.detect.outputs.docs }}
|
||||
actions:
|
||||
description: "whether actions files changed"
|
||||
value: ${{ jobs.detect.outputs.actions }}
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
detect:
|
||||
name: detect which files changed
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 3
|
||||
# Map a step output to a job output
|
||||
outputs:
|
||||
docs: ${{ steps.changes.outputs.docs }}
|
||||
backend: ${{ steps.changes.outputs.backend }}
|
||||
frontend: ${{ steps.changes.outputs.frontend }}
|
||||
docs: ${{ steps.changes.outputs.docs }}
|
||||
actions: ${{ steps.changes.outputs.actions }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check for backend file changes
|
||||
uses: dorny/paths-filter@v2
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
with:
|
||||
filters: .github/file-filters.yml
|
||||
filters: |
|
||||
backend:
|
||||
- "**/*.go"
|
||||
- "**/*.tmpl"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
|
||||
frontend:
|
||||
- "**/*.js"
|
||||
- "web_src/**"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
|
||||
docs:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
|
||||
actions:
|
||||
- ".github/workflows/*"
|
||||
|
25
.github/workflows/pull-compliance-docs.yml
vendored
25
.github/workflows/pull-compliance-docs.yml
vendored
@ -1,25 +0,0 @@
|
||||
name: compliance-docs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
uses: ./.github/workflows/files-changed.yml
|
||||
|
||||
compliance-docs:
|
||||
if: needs.files-changed.outputs.docs == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- run: make deps-frontend
|
||||
- run: make lint-md
|
||||
- run: make docs # test if build could succeed
|
27
.github/workflows/pull-compliance.yml
vendored
27
.github/workflows/pull-compliance.yml
vendored
@ -25,6 +25,7 @@ jobs:
|
||||
- run: make lint-backend
|
||||
env:
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
|
||||
lint-go-windows:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
needs: files-changed
|
||||
@ -41,6 +42,7 @@ jobs:
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
|
||||
lint-go-gogit:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
needs: files-changed
|
||||
@ -55,6 +57,7 @@ jobs:
|
||||
- run: make lint-go
|
||||
env:
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
|
||||
checks-backend:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
needs: files-changed
|
||||
@ -67,6 +70,7 @@ jobs:
|
||||
check-latest: true
|
||||
- run: make deps-backend deps-tools
|
||||
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
||||
|
||||
frontend:
|
||||
if: needs.files-changed.outputs.frontend == 'true'
|
||||
needs: files-changed
|
||||
@ -79,6 +83,7 @@ jobs:
|
||||
- run: make deps-frontend
|
||||
- run: make lint-frontend
|
||||
- run: make checks-frontend
|
||||
|
||||
backend:
|
||||
if: needs.files-changed.outputs.backend == 'true'
|
||||
needs: files-changed
|
||||
@ -113,3 +118,25 @@ jobs:
|
||||
env:
|
||||
GOOS: linux
|
||||
GOARCH: 386
|
||||
|
||||
docs:
|
||||
if: needs.files-changed.outputs.docs == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
- run: make deps-frontend
|
||||
- run: make lint-md
|
||||
- run: make docs # test if build could succeed
|
||||
|
||||
actions:
|
||||
if: needs.files-changed.outputs.actions == 'true'
|
||||
needs: files-changed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
- run: make lint-actions
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -77,7 +77,6 @@ cpu.out
|
||||
/yarn-error.log
|
||||
/npm-debug.log*
|
||||
/public/js
|
||||
/public/serviceworker.js
|
||||
/public/css
|
||||
/public/fonts
|
||||
/public/img/webpack
|
||||
|
1
.ignore
1
.ignore
@ -1,5 +1,6 @@
|
||||
*.min.css
|
||||
*.min.js
|
||||
/assets/*.json
|
||||
/modules/options/bindata.go
|
||||
/modules/public/bindata.go
|
||||
/modules/templates/bindata.go
|
||||
|
2
Makefile
2
Makefile
@ -114,7 +114,7 @@ FOMANTIC_WORK_DIR := web_src/fomantic
|
||||
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
|
||||
WEBPACK_CONFIGS := webpack.config.js
|
||||
WEBPACK_DEST := public/js/index.js public/css/index.css
|
||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack public/serviceworker.js
|
||||
WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack
|
||||
|
||||
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
||||
|
4
assets/go-licenses.json
generated
4
assets/go-licenses.json
generated
@ -525,8 +525,8 @@
|
||||
"licenseText": "Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
},
|
||||
{
|
||||
"name": "github.com/google/go-github/v51/github",
|
||||
"path": "github.com/google/go-github/v51/github/LICENSE",
|
||||
"name": "github.com/google/go-github/v52/github",
|
||||
"path": "github.com/google/go-github/v52/github/LICENSE",
|
||||
"licenseText": "Copyright (c) 2013 The go-github AUTHORS. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
|
||||
},
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/google/go-github/v51/github"
|
||||
"github.com/google/go-github/v52/github"
|
||||
"github.com/urfave/cli"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
@ -1044,7 +1044,7 @@ LEVEL = Info
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; List of reasons why a Pull Request or Issue can be locked
|
||||
;LOCK_REASONS = Too heated,Off-topic,Resolved,Spam
|
||||
;; Maximum number of pinned Issues
|
||||
;; Maximum number of pinned Issues per repo
|
||||
;; Set to 0 to disable pinning Issues
|
||||
;MAX_PINNED = 3
|
||||
|
||||
@ -1208,9 +1208,6 @@ LEVEL = Info
|
||||
;; Whether to search within description at repository search on explore page.
|
||||
;SEARCH_REPO_DESCRIPTION = true
|
||||
;;
|
||||
;; Whether to enable a Service Worker to cache frontend assets
|
||||
;USE_SERVICE_WORKER = false
|
||||
;;
|
||||
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
|
||||
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
|
||||
;ONLY_SHOW_RELEVANT_REPOS = false
|
||||
|
@ -141,7 +141,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
|
||||
### Repository - Issue (`repository.issue`)
|
||||
|
||||
- `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked
|
||||
- `MAX_PINNED`: **3**: Maximum number of pinned Issues. Set to 0 to disable pinning Issues.
|
||||
- `MAX_PINNED`: **3**: Maximum number of pinned Issues per Repo. Set to 0 to disable pinning Issues.
|
||||
|
||||
### Repository - Upload (`repository.upload`)
|
||||
|
||||
@ -230,7 +230,6 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
add it to this config.
|
||||
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
||||
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
|
||||
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
|
||||
- `ONLY_SHOW_RELEVANT_REPOS`: **false** Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
|
||||
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
|
||||
|
||||
|
@ -301,4 +301,4 @@ You can try it out using [the online demo](https://try.gitea.io/).
|
||||
|
||||
## Integrated support
|
||||
|
||||
Please visit [AWESOME GITEA] (https://gitea.com/gitea/awesome-gitea/) to get more third-party integrated support
|
||||
Please visit [Awesome Gitea](https://gitea.com/gitea/awesome-gitea/) to get more third-party integrated support
|
||||
|
8
go.mod
8
go.mod
@ -55,7 +55,7 @@ require (
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/google/go-github/v51 v51.0.0
|
||||
github.com/google/go-github/v52 v52.0.0
|
||||
github.com/google/pprof v0.0.0-20230502171905-255e3b9b56de
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/feeds v1.1.1
|
||||
@ -107,10 +107,10 @@ require (
|
||||
github.com/yuin/goldmark v1.5.4
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
golang.org/x/crypto v0.8.0
|
||||
golang.org/x/crypto v0.9.0
|
||||
golang.org/x/image v0.7.0
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/oauth2 v0.7.0
|
||||
golang.org/x/oauth2 v0.8.0
|
||||
golang.org/x/sys v0.8.0
|
||||
golang.org/x/text v0.9.0
|
||||
golang.org/x/tools v0.8.0
|
||||
@ -136,7 +136,7 @@ require (
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
|
18
go.sum
18
go.sum
@ -105,8 +105,8 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq
|
||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756 h1:L6S7kR7SlhQKplIBpkra3s6yhcZV51lhRnXmYc4HohI=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 h1:JMDGhoQvXNTqH6Y3MC0IUw6tcZvaUdujNqzK2HYWZc8=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@ -227,6 +227,7 @@ github.com/bufbuild/connect-go v1.7.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrI
|
||||
github.com/buildkite/terminal-to-html/v3 v3.7.0 h1:chdLUSpiOj/A4v3dzxyOqixXI6aw7IDA6Dk77FXsvNU=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.7.0/go.mod h1:g0ME1XqbkBSgXR9YmlIHcJIjzaMyWW+HbsG0rPb5puo=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE=
|
||||
github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
@ -564,8 +565,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v51 v51.0.0 h1:KCjsbgPV28VoRftdP+K2mQL16jniUsLAJknsOVKwHyU=
|
||||
github.com/google/go-github/v51 v51.0.0/go.mod h1:kZj/rn/c1lSUbr/PFWl2hhusPV7a5XNYKcwPrd5L3Us=
|
||||
github.com/google/go-github/v52 v52.0.0 h1:uyGWOY+jMQ8GVGSX8dkSwCzlehU3WfdxQ7GweO/JP7M=
|
||||
github.com/google/go-github/v52 v52.0.0/go.mod h1:WJV6VEEUPuMo5pXqqa2ZCZEdbQqua4zAk2MZTIo+m+4=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
||||
@ -1318,10 +1319,11 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -1430,8 +1432,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -69,7 +69,11 @@ func (r *ActionRunner) BelongsToOwnerType() types.OwnerType {
|
||||
return types.OwnerTypeRepository
|
||||
}
|
||||
if r.OwnerID != 0 {
|
||||
return types.OwnerTypeOrganization
|
||||
if r.Owner.Type == user_model.UserTypeOrganization {
|
||||
return types.OwnerTypeOrganization
|
||||
} else if r.Owner.Type == user_model.UserTypeIndividual {
|
||||
return types.OwnerTypeIndividual
|
||||
}
|
||||
}
|
||||
return types.OwnerTypeSystemGlobal
|
||||
}
|
||||
|
@ -687,6 +687,8 @@ func (issue *Issue) HasOriginalAuthor() bool {
|
||||
return issue.OriginalAuthor != "" && issue.OriginalAuthorID != 0
|
||||
}
|
||||
|
||||
var ErrIssueMaxPinReached = util.NewInvalidArgumentErrorf("the max number of pinned issues has been readched")
|
||||
|
||||
// IsPinned returns if a Issue is pinned
|
||||
func (issue *Issue) IsPinned() bool {
|
||||
return issue.PinOrder != 0
|
||||
@ -707,7 +709,7 @@ func (issue *Issue) Pin(ctx context.Context, user *user_model.User) error {
|
||||
|
||||
// Check if the maximum allowed Pins reached
|
||||
if maxPin >= setting.Repository.Issue.MaxPinned {
|
||||
return fmt.Errorf("You have reached the max number of pinned Issues")
|
||||
return ErrIssueMaxPinReached
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(ctx).Table("issue").
|
||||
@ -856,10 +858,15 @@ func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) ([]*Issue,
|
||||
// IsNewPinnedAllowed returns if a new Issue or Pull request can be pinned
|
||||
func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) {
|
||||
var maxPin int
|
||||
_, err := db.GetEngine(ctx).SQL("SELECT MAX(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ?", repoID, isPull).Get(&maxPin)
|
||||
_, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ? AND pin_order > 0", repoID, isPull).Get(&maxPin)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return maxPin < setting.Repository.Issue.MaxPinned, nil
|
||||
}
|
||||
|
||||
// IsErrIssueMaxPinReached returns if the error is, that the User can't pin more Issues
|
||||
func IsErrIssueMaxPinReached(err error) bool {
|
||||
return err == ErrIssueMaxPinReached
|
||||
}
|
||||
|
@ -53,6 +53,11 @@ func (ref *Reference) Commit() (*Commit, error) {
|
||||
return ref.repo.getCommit(ref.Object)
|
||||
}
|
||||
|
||||
// ShortName returns the short name of the reference
|
||||
func (ref *Reference) ShortName() string {
|
||||
return RefName(ref.Name).ShortName()
|
||||
}
|
||||
|
||||
// RefGroup returns the group type of the reference
|
||||
func (ref *Reference) RefGroup() string {
|
||||
return RefName(ref.Name).RefGroup()
|
||||
|
@ -32,7 +32,6 @@ var UI = struct {
|
||||
CustomEmojis []string
|
||||
CustomEmojisMap map[string]string `ini:"-"`
|
||||
SearchRepoDescription bool
|
||||
UseServiceWorker bool
|
||||
OnlyShowRelevantRepos bool
|
||||
|
||||
Notification struct {
|
||||
@ -136,7 +135,6 @@ func loadUIFrom(rootCfg ConfigProvider) {
|
||||
UI.ShowUserEmail = sec.Key("SHOW_USER_EMAIL").MustBool(true)
|
||||
UI.DefaultShowFullName = sec.Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
|
||||
UI.SearchRepoDescription = sec.Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
|
||||
UI.UseServiceWorker = sec.Key("USE_SERVICE_WORKER").MustBool(false)
|
||||
|
||||
// OnlyShowRelevantRepos=false is important for many private/enterprise instances,
|
||||
// because many private repositories do not have "description/topic", users just want to search by their names.
|
||||
|
@ -127,9 +127,6 @@ func NewFuncMap() template.FuncMap {
|
||||
"MetaKeywords": func() string {
|
||||
return setting.UI.Meta.Keywords
|
||||
},
|
||||
"UseServiceWorker": func() bool {
|
||||
return setting.UI.UseServiceWorker
|
||||
},
|
||||
"EnableTimetracking": func() bool {
|
||||
return setting.Service.EnableTimetracking
|
||||
},
|
||||
|
@ -125,6 +125,10 @@ concept_user_individual = Individual
|
||||
concept_code_repository = Repository
|
||||
concept_user_organization = Organization
|
||||
|
||||
show_timestamps = Show timestamps
|
||||
show_log_seconds = Show seconds
|
||||
show_full_screen = Show full screen
|
||||
|
||||
[aria]
|
||||
navbar = Navigation Bar
|
||||
footer = Footer
|
||||
|
23
package-lock.json
generated
23
package-lock.json
generated
@ -51,8 +51,6 @@
|
||||
"vue3-calendar-heatmap": "2.0.5",
|
||||
"webpack": "5.84.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"workbox-routing": "6.6.0",
|
||||
"workbox-strategies": "6.6.0",
|
||||
"wrap-ansi": "8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -11045,27 +11043,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/workbox-core": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.6.0.tgz",
|
||||
"integrity": "sha512-GDtFRF7Yg3DD859PMbPAYPeJyg5gJYXuBQAC+wyrWuuXgpfoOrIQIvFRZnQ7+czTIQjIr1DhLEGFzZanAT/3bQ=="
|
||||
},
|
||||
"node_modules/workbox-routing": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.6.0.tgz",
|
||||
"integrity": "sha512-x8gdN7VDBiLC03izAZRfU+WKUXJnbqt6PG9Uh0XuPRzJPpZGLKce/FkOX95dWHRpOHWLEq8RXzjW0O+POSkKvw==",
|
||||
"dependencies": {
|
||||
"workbox-core": "6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/workbox-strategies": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.6.0.tgz",
|
||||
"integrity": "sha512-eC07XGuINAKUWDnZeIPdRdVja4JQtTuc35TZ8SwMb1ztjp7Ddq2CJ4yqLvWzFWGlYI7CG/YGqaETntTxBGdKgQ==",
|
||||
"dependencies": {
|
||||
"workbox-core": "6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
||||
|
@ -51,8 +51,6 @@
|
||||
"vue3-calendar-heatmap": "2.0.5",
|
||||
"webpack": "5.84.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"workbox-routing": "6.6.0",
|
||||
"workbox-strategies": "6.6.0",
|
||||
"wrap-ansi": "8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -45,6 +45,8 @@ func PinIssue(ctx *context.APIContext) {
|
||||
if err != nil {
|
||||
if issues_model.IsErrIssueNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else if issues_model.IsErrIssueMaxPinReached(err) {
|
||||
ctx.Error(http.StatusBadRequest, "MaxPinReached", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err)
|
||||
}
|
||||
@ -55,11 +57,13 @@ func PinIssue(ctx *context.APIContext) {
|
||||
err = issue.LoadRepo(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.Pin(ctx, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "PinIssue", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
@ -108,11 +112,13 @@ func UnpinIssue(ctx *context.APIContext) {
|
||||
err = issue.LoadRepo(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.Unpin(ctx, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UnpinIssue", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
@ -166,6 +172,7 @@ func MoveIssuePin(ctx *context.APIContext) {
|
||||
err = issue.MovePin(ctx, int(ctx.ParamsInt64(":position")))
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "MovePin", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
@ -193,12 +200,12 @@ func ListPinnedIssues(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/IssueList"
|
||||
issues, err := issues_model.GetPinnedIssues(ctx, ctx.Repo.Repository.ID, false)
|
||||
|
||||
if err == nil {
|
||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
|
||||
} else {
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadPinnedIssues", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
|
||||
}
|
||||
|
||||
// ListPinnedPullRequests returns a list of all pinned PRs
|
||||
@ -225,6 +232,7 @@ func ListPinnedPullRequests(ctx *context.APIContext) {
|
||||
issues, err := issues_model.GetPinnedIssues(ctx, ctx.Repo.Repository.ID, true)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadPinnedPullRequests", err)
|
||||
return
|
||||
}
|
||||
|
||||
apiPrs := make([]*api.PullRequest, len(issues))
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// IssuePinOrUnpin pin or unpin a Issue
|
||||
@ -19,12 +20,14 @@ func IssuePinOrUnpin(ctx *context.Context) {
|
||||
err := issue.LoadRepo(ctx)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.PinOrUnpin(ctx, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@ -33,9 +36,10 @@ func IssuePinOrUnpin(ctx *context.Context) {
|
||||
|
||||
// IssueUnpin unpins a Issue
|
||||
func IssueUnpin(ctx *context.Context) {
|
||||
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusNoContent)
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@ -43,12 +47,15 @@ func IssueUnpin(ctx *context.Context) {
|
||||
err = issue.LoadRepo(ctx)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.Unpin(ctx, ctx.Doer)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
@ -69,18 +76,21 @@ func IssuePinMove(ctx *context.Context) {
|
||||
form := &movePinIssueForm{}
|
||||
if err := json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
issue, err := issues_model.GetIssueByID(ctx, form.ID)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = issue.MovePin(ctx, form.Position)
|
||||
if err != nil {
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,11 @@ const (
|
||||
tplRepoRunners base.TplName = "repo/settings/actions"
|
||||
tplOrgRunners base.TplName = "org/settings/actions"
|
||||
tplAdminRunners base.TplName = "admin/actions"
|
||||
tplUserRunners base.TplName = "user/settings/actions"
|
||||
tplRepoRunnerEdit base.TplName = "repo/settings/runner_edit"
|
||||
tplOrgRunnerEdit base.TplName = "org/settings/runners_edit"
|
||||
tplAdminRunnerEdit base.TplName = "admin/runners/edit"
|
||||
tplUserRunnerEdit base.TplName = "user/settings/runner_edit"
|
||||
)
|
||||
|
||||
type runnersCtx struct {
|
||||
@ -32,6 +34,7 @@ type runnersCtx struct {
|
||||
IsRepo bool
|
||||
IsOrg bool
|
||||
IsAdmin bool
|
||||
IsUser bool
|
||||
RunnersTemplate base.TplName
|
||||
RunnerEditTemplate base.TplName
|
||||
RedirectLink string
|
||||
@ -71,6 +74,17 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsUserSettings"] == true {
|
||||
return &runnersCtx{
|
||||
OwnerID: ctx.Doer.ID,
|
||||
RepoID: 0,
|
||||
IsUser: true,
|
||||
RunnersTemplate: tplUserRunners,
|
||||
RunnerEditTemplate: tplUserRunnerEdit,
|
||||
RedirectLink: setting.AppSubURL + "/user/settings/actions/runners/",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unable to set Runners context")
|
||||
}
|
||||
|
||||
@ -102,7 +116,7 @@ func Runners(ctx *context.Context) {
|
||||
if rCtx.IsRepo {
|
||||
opts.RepoID = rCtx.RepoID
|
||||
opts.WithAvailable = true
|
||||
} else if rCtx.IsOrg {
|
||||
} else if rCtx.IsOrg || rCtx.IsUser {
|
||||
opts.OwnerID = rCtx.OwnerID
|
||||
opts.WithAvailable = true
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ import (
|
||||
)
|
||||
|
||||
func RedirectToDefaultSetting(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/actions/secrets")
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/actions/runners")
|
||||
}
|
@ -492,6 +492,7 @@ func registerRoutes(m *web.Route) {
|
||||
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", user_setting.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
}, actions.MustEnableActions)
|
||||
|
||||
@ -1025,8 +1026,8 @@ func registerRoutes(m *web.Route) {
|
||||
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation)
|
||||
m.Post("/attachments", repo.UploadIssueAttachment)
|
||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||
m.Delete("/unpin/{id}", reqRepoAdmin, repo.IssueUnpin)
|
||||
m.Post("/pin_move", reqRepoAdmin, repo.IssuePinMove)
|
||||
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
||||
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
|
||||
}, context.RepoMustNotBeArchived())
|
||||
m.Group("/comments/{id}", func() {
|
||||
m.Post("", repo.UpdateCommentContent)
|
||||
|
@ -7,7 +7,7 @@ package migrations
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/google/go-github/v51/github"
|
||||
"github.com/google/go-github/v52/github"
|
||||
)
|
||||
|
||||
// ErrRepoNotCreated returns the error that repository not created
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/google/go-github/v51/github"
|
||||
"github.com/google/go-github/v52/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@ -256,11 +256,11 @@ func (g *GithubDownloaderV3) GetMilestones() ([]*base.Milestone, error) {
|
||||
milestones = append(milestones, &base.Milestone{
|
||||
Title: m.GetTitle(),
|
||||
Description: m.GetDescription(),
|
||||
Deadline: convertGithubTimestampToTime(m.DueOn),
|
||||
Deadline: m.DueOn.GetTime(),
|
||||
State: state,
|
||||
Created: m.GetCreatedAt().Time,
|
||||
Updated: convertGithubTimestampToTime(m.UpdatedAt),
|
||||
Closed: convertGithubTimestampToTime(m.ClosedAt),
|
||||
Updated: m.UpdatedAt.GetTime(),
|
||||
Closed: m.ClosedAt.GetTime(),
|
||||
})
|
||||
}
|
||||
if len(ms) < perPage {
|
||||
@ -715,11 +715,11 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq
|
||||
State: pr.GetState(),
|
||||
Created: pr.GetCreatedAt().Time,
|
||||
Updated: pr.GetUpdatedAt().Time,
|
||||
Closed: convertGithubTimestampToTime(pr.ClosedAt),
|
||||
Closed: pr.ClosedAt.GetTime(),
|
||||
Labels: labels,
|
||||
Merged: pr.MergedAt != nil,
|
||||
MergeCommitSHA: pr.GetMergeCommitSHA(),
|
||||
MergedTime: convertGithubTimestampToTime(pr.MergedAt),
|
||||
MergedTime: pr.MergedAt.GetTime(),
|
||||
IsLocked: pr.ActiveLockReason != nil,
|
||||
Head: base.PullRequestBranch{
|
||||
Ref: pr.GetHead().GetRef(),
|
||||
@ -878,10 +878,3 @@ func (g *GithubDownloaderV3) GetReviews(reviewable base.Reviewable) ([]*base.Rev
|
||||
}
|
||||
return allReviews, nil
|
||||
}
|
||||
|
||||
func convertGithubTimestampToTime(t *github.Timestamp) *time.Time {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
return &t.Time
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<form method="post" action="{{AppSubUrl}}/admin">
|
||||
<table class="ui very basic striped table unstackable">
|
||||
<table class="ui very basic striped table unstackable gt-mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<div class="ui attached table segment">
|
||||
<form method="post" action="{{AppSubUrl}}/admin">
|
||||
{{.CsrfTokenHtml}}
|
||||
<table class="ui very basic table gt-px-4">
|
||||
<table class="ui very basic table gt-mt-0 gt-px-4">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{.locale.Tr "admin.dashboard.delete_inactive_accounts"}}</td>
|
||||
|
@ -166,7 +166,7 @@
|
||||
<label>{{.locale.Tr "settings.lookup_avatar_by_mail"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if .Err_Gravatar}}error{{end}}">
|
||||
<div class="field gt-pl-4 {{if .Err_Gravatar}}error{{end}}">
|
||||
<label for="gravatar">Avatar {{.locale.Tr "email"}}</label>
|
||||
<input id="gravatar" name="gravatar" value="{{.User.AvatarEmail}}">
|
||||
</div>
|
||||
@ -179,7 +179,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inline field">
|
||||
<div class="inline field gt-pl-4">
|
||||
<label for="avatar">{{.locale.Tr "settings.choose_new_avatar"}}</label>
|
||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
||||
</div>
|
||||
@ -197,17 +197,17 @@
|
||||
{{svg "octicon-trash"}}
|
||||
{{.locale.Tr "settings.delete_account_title"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "settings.delete_account_desc"}}</p>
|
||||
</div>
|
||||
<form class="ui form" method="POST" action="{{.Link}}/delete">
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="purge">{{.locale.Tr "admin.users.purge"}}</label>
|
||||
<input name="purge" type="checkbox">
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "settings.delete_account_desc"}}</p>
|
||||
{{$.CsrfTokenHtml}}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="purge">{{.locale.Tr "admin.users.purge"}}</label>
|
||||
<input name="purge" type="checkbox">
|
||||
</div>
|
||||
<p class="help">{{.locale.Tr "admin.users.purge_help"}}</p>
|
||||
</div>
|
||||
<p class="help">{{.locale.Tr "admin.users.purge_help"}}</p>
|
||||
</div>
|
||||
{{template "base/modal_actions_confirm" .}}
|
||||
</form>
|
||||
|
@ -12,7 +12,6 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly.
|
||||
assetUrlPrefix: '{{AssetUrlPrefix}}',
|
||||
runModeIsProd: {{.RunModeIsProd}},
|
||||
customEmojis: {{CustomEmojis}},
|
||||
useServiceWorker: {{UseServiceWorker}},
|
||||
csrfToken: '{{.CsrfToken}}',
|
||||
pageData: {{.PageData}},
|
||||
notificationSettings: {{NotificationSettings}}, {{/*a map provided by NewFuncMap in helper.go*/}}
|
||||
|
@ -19,6 +19,9 @@
|
||||
data-locale-status-skipped="{{.locale.Tr "actions.status.skipped"}}"
|
||||
data-locale-status-blocked="{{.locale.Tr "actions.status.blocked"}}"
|
||||
data-locale-artifacts-title="{{$.locale.Tr "artifacts"}}"
|
||||
data-locale-show-timestamps="{{.locale.Tr "show_timestamps"}}"
|
||||
data-locale-show-log-seconds="{{.locale.Tr "show_log_seconds"}}"
|
||||
data-locale-show-full-screen="{{.locale.Tr "show_full_screen"}}"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -45,33 +45,31 @@
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<script id="diff-data-script">
|
||||
(() => {
|
||||
const diffData = {
|
||||
files: [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}}},{{end}}],
|
||||
isIncomplete: {{.Diff.IsIncomplete}},
|
||||
tooManyFilesMessage: "{{$.locale.Tr "repo.diff.too_many_files"}}",
|
||||
binaryFileMessage: "{{$.locale.Tr "repo.diff.bin"}}",
|
||||
showMoreMessage: "{{.locale.Tr "repo.diff.show_more"}}",
|
||||
statisticsMessage: "{{.locale.Tr "repo.diff.stats_desc_file"}}",
|
||||
fileTreeIsVisible: false,
|
||||
fileListIsVisible: false,
|
||||
isLoadingNewData: false,
|
||||
diffEnd: {{.Diff.End}},
|
||||
link: "{{$.Link}}"
|
||||
};
|
||||
if(window.config.pageData.diffFileInfo) {
|
||||
// Page is already loaded - add the data to our existing data
|
||||
window.config.pageData.diffFileInfo.files.push(...diffData.files);
|
||||
window.config.pageData.diffFileInfo.isIncomplete = diffData.isIncomplete;
|
||||
window.config.pageData.diffFileInfo.diffEnd = diffData.diffEnd;
|
||||
window.config.pageData.diffFileInfo.link = diffData.link;
|
||||
} else {
|
||||
// new load of page - populate initial data
|
||||
window.config.pageData.diffFileInfo = diffData;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script id="diff-data-script" type="module">
|
||||
const diffDataFiles = [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}}},{{end}}];
|
||||
const diffData = {
|
||||
isIncomplete: {{.Diff.IsIncomplete}},
|
||||
tooManyFilesMessage: "{{$.locale.Tr "repo.diff.too_many_files"}}",
|
||||
binaryFileMessage: "{{$.locale.Tr "repo.diff.bin"}}",
|
||||
showMoreMessage: "{{.locale.Tr "repo.diff.show_more"}}",
|
||||
statisticsMessage: "{{.locale.Tr "repo.diff.stats_desc_file"}}",
|
||||
linkLoadMore: "{{$.Link}}?skip-to={{.Diff.End}}&file-only=true",
|
||||
};
|
||||
|
||||
// for first time loading, the diffFileInfo is a plain object
|
||||
// after the Vue component is mounted, the diffFileInfo is a reactive object
|
||||
// keep in mind that this script block would be executed many times when loading more files, by "loadMoreFiles"
|
||||
let diffFileInfo = window.config.pageData.diffFileInfo || {
|
||||
files:[],
|
||||
fileTreeIsVisible: false,
|
||||
fileListIsVisible: false,
|
||||
isLoadingNewData: false,
|
||||
selectedItem: '',
|
||||
};
|
||||
diffFileInfo = Object.assign(diffFileInfo, diffData);
|
||||
diffFileInfo.files.push(...diffDataFiles);
|
||||
window.config.pageData.diffFileInfo = diffFileInfo;
|
||||
</script>
|
||||
<div id="diff-file-list"></div>
|
||||
<div id="diff-container">
|
||||
<div id="diff-file-tree" class="gt-hidden"></div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{if .PinnedIssues}}
|
||||
<div id="issue-pins" {{if .IsRepoAdmin}}data-is-repo-admin{{end}}>
|
||||
{{range .PinnedIssues}}
|
||||
<div class="pinned-issue-card gt-word-break" data-move-url="{{$.Link}}/pin_move" data-issue-id="{{.ID}}">
|
||||
<div class="pinned-issue-card gt-word-break" data-move-url="{{$.Link}}/move_pin" data-issue-id="{{.ID}}">
|
||||
{{if eq $.Project.CardType 1}}
|
||||
<div class="card-attachment-images">
|
||||
{{range (index $.issuesAttachmentMap .ID)}}
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<a class="pinned-issue-title muted issue-title" href="{{.Link}}">{{.Title | RenderEmoji $.Context | RenderCodeBlock}}</a>
|
||||
{{if $.IsRepoAdmin}}
|
||||
<a role="button" class="pinned-issue-unpin muted gt-df gt-ac" data-tooltip-content={{$.locale.Tr "repo.issues.unpin_issue"}} data-issue-id="{{.ID}}" data-unpin-url="{{$.Link}}/unpin/{{.ID}}">
|
||||
<a role="button" class="pinned-issue-unpin muted gt-df gt-ac" data-tooltip-content={{$.locale.Tr "repo.issues.unpin_issue"}} data-issue-id="{{.ID}}" data-unpin-url="{{$.Link}}/unpin/{{.Index}}">
|
||||
{{svg "octicon-x" 16}}
|
||||
</a>
|
||||
{{end}}
|
||||
|
@ -330,7 +330,7 @@
|
||||
<label>{{.locale.Tr "repo.settings.use_external_wiki"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box">
|
||||
<div class="field gt-pl-4 {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box">
|
||||
<label for="external_wiki_url">{{.locale.Tr "repo.settings.external_wiki_url"}}</label>
|
||||
<input id="external_wiki_url" name="external_wiki_url" type="url" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}">
|
||||
<p class="help">{{.locale.Tr "repo.settings.external_wiki_url_desc"}}</p>
|
||||
@ -362,7 +362,7 @@
|
||||
<label>{{.locale.Tr "repo.settings.use_internal_issue_tracker"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
|
||||
<div class="field gt-pl-4 {{if (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
|
||||
{{if .Repository.CanEnableTimetracker}}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
@ -398,7 +398,7 @@
|
||||
<label>{{.locale.Tr "repo.settings.use_external_issue_tracker"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box">
|
||||
<div class="field gt-pl-4 {{if not (.Repository.UnitEnabled $.Context $.UnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box">
|
||||
<div class="field">
|
||||
<label for="external_tracker_url">{{.locale.Tr "repo.settings.external_tracker_url"}}</label>
|
||||
<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit $.Context $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}">
|
||||
|
@ -2,6 +2,8 @@
|
||||
<div class="user-setting-content">
|
||||
{{if eq .PageType "secrets"}}
|
||||
{{template "shared/secrets/add_list" .}}
|
||||
{{else if eq .PageType "runners"}}
|
||||
{{template "shared/actions/runner_list" .}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
<div class="item">
|
||||
{{.locale.Tr "actions.actions"}}
|
||||
<div class="menu">
|
||||
<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/user/settings/actions/runners">
|
||||
{{.locale.Tr "actions.runners"}}
|
||||
</a>
|
||||
<a class="{{if .PageIsSharedSettingsSecrets}}active {{end}}item" href="{{AppSubUrl}}/user/settings/actions/secrets">
|
||||
{{.locale.Tr "secrets.secrets"}}
|
||||
</a>
|
||||
|
@ -105,7 +105,7 @@
|
||||
<label>{{.locale.Tr "settings.lookup_avatar_by_mail"}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if .Err_Gravatar}}error{{end}}">
|
||||
<div class="field gt-pl-4 {{if .Err_Gravatar}}error{{end}}">
|
||||
<label for="gravatar">Avatar {{.locale.Tr "email"}}</label>
|
||||
<input id="gravatar" name="gravatar" value="{{.SignedUser.AvatarEmail}}">
|
||||
</div>
|
||||
@ -118,7 +118,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inline field">
|
||||
<div class="inline field gt-pl-4">
|
||||
<label for="avatar">{{.locale.Tr "settings.choose_new_avatar"}}</label>
|
||||
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
||||
</div>
|
||||
|
5
templates/user/settings/runner_edit.tmpl
Normal file
5
templates/user/settings/runner_edit.tmpl
Normal file
@ -0,0 +1,5 @@
|
||||
{{template "user/settings/layout_head" (dict "ctxData" . "pageClass" "user settings runners")}}
|
||||
<div class="user-setting-content">
|
||||
{{template "shared/actions/runner_edit" .}}
|
||||
</div>
|
||||
{{template "user/settings/layout_footer" .}}
|
@ -74,12 +74,15 @@
|
||||
--color-secondary-alpha-90: #dededee1;
|
||||
--color-secondary-hover: var(--color-secondary-dark-1);
|
||||
--color-secondary-active: var(--color-secondary-dark-2);
|
||||
/* console colors */
|
||||
--color-console-fg: #ffffff;
|
||||
--color-console-bg: #252a2f;
|
||||
--color-console-border: #ffffff16;
|
||||
/* console colors - used for actions console and console files */
|
||||
--color-console-fg: #eeeff2;
|
||||
--color-console-fg-subtle: #959cab;
|
||||
--color-console-bg: #262936;
|
||||
--color-console-border: #383c47;
|
||||
--color-console-hover-bg: #ffffff16;
|
||||
--color-console-active-bg: #353a3f;
|
||||
--color-console-active-bg: #454a57;
|
||||
--color-console-menu-bg: #383c47;
|
||||
--color-console-menu-border: #5c6374;
|
||||
/* named colors */
|
||||
--color-red: #db2828;
|
||||
--color-orange: #f2711c;
|
||||
@ -553,7 +556,7 @@ a.label,
|
||||
color: var(--color-text-light-3);
|
||||
}
|
||||
|
||||
.ui.menu .item::before {
|
||||
.ui.menu .item::before, .ui.vertical.menu .item::before {
|
||||
background: var(--color-secondary);
|
||||
}
|
||||
|
||||
@ -603,6 +606,7 @@ a.label,
|
||||
.ui.dropdown .menu .active.item {
|
||||
color: var(--color-text);
|
||||
background: var(--color-active);
|
||||
border-radius: 0;
|
||||
font-weight: var(--font-weight-normal);
|
||||
}
|
||||
|
||||
@ -847,6 +851,7 @@ a.label,
|
||||
|
||||
.ui.table > thead > tr > th {
|
||||
background: var(--color-box-header);
|
||||
border-color: var(--color-secondary);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
|
@ -3419,14 +3419,6 @@ tbody.commit-list {
|
||||
background: var(--color-card);
|
||||
}
|
||||
|
||||
.pinned-issue-card .meta a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.pinned-issue-card .meta a:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.pinned-issue-icon,
|
||||
.pinned-issue-unpin {
|
||||
margin-top: 1px;
|
||||
|
@ -60,12 +60,15 @@
|
||||
--color-secondary-alpha-90: #525767e1;
|
||||
--color-secondary-hover: var(--color-secondary-light-1);
|
||||
--color-secondary-active: var(--color-secondary-light-2);
|
||||
/* console colors */
|
||||
--color-console-fg: #ffffff;
|
||||
/* console colors - used for actions console and console files */
|
||||
--color-console-fg: #eeeff2;
|
||||
--color-console-fg-subtle: #959cab;
|
||||
--color-console-bg: #262936;
|
||||
--color-console-border: #ffffff16;
|
||||
--color-console-border: #383c47;
|
||||
--color-console-hover-bg: #ffffff16;
|
||||
--color-console-active-bg: #383c47;
|
||||
--color-console-active-bg: #454a57;
|
||||
--color-console-menu-bg: #383c47;
|
||||
--color-console-menu-border: #5c6374;
|
||||
/* named colors */
|
||||
--color-red: #cc4848;
|
||||
--color-orange: #cc580c;
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<ol class="diff-detail-box diff-stats gt-m-0" ref="root" v-if="fileListIsVisible">
|
||||
<li v-for="file in files" :key="file.NameHash">
|
||||
<ol class="diff-detail-box diff-stats gt-m-0" ref="root" v-if="store.fileListIsVisible">
|
||||
<li v-for="file in store.files" :key="file.NameHash">
|
||||
<div class="gt-font-semibold gt-df gt-ac pull-right">
|
||||
<span v-if="file.IsBin" class="gt-ml-1 gt-mr-3">{{ binaryFileMessage }}</span>
|
||||
<span v-if="file.IsBin" class="gt-ml-1 gt-mr-3">{{ store.binaryFileMessage }}</span>
|
||||
{{ file.IsBin ? '' : file.Addition + file.Deletion }}
|
||||
<span v-if="!file.IsBin" class="diff-stats-bar gt-mx-3" :data-tooltip-content="statisticsMessage.replace('%d', (file.Addition + file.Deletion)).replace('%d', file.Addition).replace('%d', file.Deletion)">
|
||||
<span v-if="!file.IsBin" class="diff-stats-bar gt-mx-3" :data-tooltip-content="store.statisticsMessage.replace('%d', (file.Addition + file.Deletion)).replace('%d', file.Addition).replace('%d', file.Deletion)">
|
||||
<div class="diff-stats-add-bar" :style="{ 'width': diffStatsWidth(file.Addition, file.Deletion) }"/>
|
||||
</span>
|
||||
</div>
|
||||
@ -12,22 +12,21 @@
|
||||
<span :class="['status', diffTypeToString(file.Type)]" :data-tooltip-content="diffTypeToString(file.Type)"> </span>
|
||||
<a class="file gt-mono" :href="'#diff-' + file.NameHash">{{ file.Name }}</a>
|
||||
</li>
|
||||
<li v-if="isIncomplete" id="diff-too-many-files-stats" class="gt-pt-2">
|
||||
<span class="file gt-df gt-ac gt-sb">{{ tooManyFilesMessage }}
|
||||
<a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a>
|
||||
<li v-if="store.isIncomplete" class="gt-pt-2">
|
||||
<span class="file gt-df gt-ac gt-sb">{{ store.tooManyFilesMessage }}
|
||||
<a :class="['ui', 'basic', 'tiny', 'button', store.isLoadingNewData ? 'disabled' : '']" @click.stop="loadMoreData">{{ store.showMoreMessage }}</a>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {doLoadMoreFiles} from '../features/repo-diff.js';
|
||||
|
||||
const {pageData} = window.config;
|
||||
import {loadMoreFiles} from '../features/repo-diff.js';
|
||||
import {diffTreeStore} from '../modules/stores.js';
|
||||
|
||||
export default {
|
||||
data: () => {
|
||||
return pageData.diffFileInfo;
|
||||
return {store: diffTreeStore()};
|
||||
},
|
||||
mounted() {
|
||||
document.getElementById('show-file-list-btn').addEventListener('click', this.toggleFileList);
|
||||
@ -37,7 +36,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
toggleFileList() {
|
||||
this.fileListIsVisible = !this.fileListIsVisible;
|
||||
this.store.fileListIsVisible = !this.store.fileListIsVisible;
|
||||
},
|
||||
diffTypeToString(pType) {
|
||||
const diffTypes = {
|
||||
@ -53,10 +52,7 @@ export default {
|
||||
return `${adds / (adds + dels) * 100}%`;
|
||||
},
|
||||
loadMoreData() {
|
||||
this.isLoadingNewData = true;
|
||||
doLoadMoreFiles(this.link, this.diffEnd, () => {
|
||||
this.isLoadingNewData = false;
|
||||
});
|
||||
loadMoreFiles(this.store.linkLoadMore);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -1,42 +1,33 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="fileTreeIsVisible"
|
||||
class="gt-mr-3 gt-mt-3 diff-detail-box"
|
||||
>
|
||||
<div v-if="store.fileTreeIsVisible" class="gt-mr-3 gt-mt-3 diff-detail-box">
|
||||
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
|
||||
<div class="ui list">
|
||||
<DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item"/>
|
||||
</div>
|
||||
<div v-if="isIncomplete" id="diff-too-many-files-stats" class="gt-pt-2">
|
||||
<span class="gt-mr-2">{{ tooManyFilesMessage }}</span><a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a>
|
||||
<div v-if="store.isIncomplete" class="gt-pt-2">
|
||||
<a :class="['ui', 'basic', 'tiny', 'button', store.isLoadingNewData ? 'disabled' : '']" @click.stop="loadMoreData">{{ store.showMoreMessage }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DiffFileTreeItem from './DiffFileTreeItem.vue';
|
||||
import {doLoadMoreFiles} from '../features/repo-diff.js';
|
||||
import {loadMoreFiles} from '../features/repo-diff.js';
|
||||
import {toggleElem} from '../utils/dom.js';
|
||||
import {DiffTreeStore} from '../modules/stores.js';
|
||||
import {diffTreeStore} from '../modules/stores.js';
|
||||
import {setFileFolding} from '../features/file-fold.js';
|
||||
|
||||
const {pageData} = window.config;
|
||||
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
|
||||
|
||||
export default {
|
||||
components: {DiffFileTreeItem},
|
||||
data: () => {
|
||||
const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
|
||||
pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible;
|
||||
return {
|
||||
...pageData.diffFileInfo,
|
||||
store: DiffTreeStore,
|
||||
};
|
||||
return {store: diffTreeStore()};
|
||||
},
|
||||
computed: {
|
||||
fileTree() {
|
||||
const result = [];
|
||||
for (const file of this.files) {
|
||||
for (const file of this.store.files) {
|
||||
// Split file into directories
|
||||
const splits = file.Name.split('/');
|
||||
let index = 0;
|
||||
@ -98,9 +89,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// replace the pageData.diffFileInfo.files with our watched data so we get updates
|
||||
pageData.diffFileInfo.files = this.files;
|
||||
|
||||
this.store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
|
||||
document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility);
|
||||
|
||||
this.hashChangeListener = () => {
|
||||
@ -124,12 +113,12 @@ export default {
|
||||
}
|
||||
},
|
||||
toggleVisibility() {
|
||||
this.updateVisibility(!this.fileTreeIsVisible);
|
||||
this.updateVisibility(!this.store.fileTreeIsVisible);
|
||||
},
|
||||
updateVisibility(visible) {
|
||||
this.fileTreeIsVisible = visible;
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, this.fileTreeIsVisible);
|
||||
this.updateState(this.fileTreeIsVisible);
|
||||
this.store.fileTreeIsVisible = visible;
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, this.store.fileTreeIsVisible);
|
||||
this.updateState(this.store.fileTreeIsVisible);
|
||||
},
|
||||
updateState(visible) {
|
||||
const btn = document.querySelector('.diff-toggle-file-tree-button');
|
||||
@ -142,12 +131,7 @@ export default {
|
||||
toggleElem(toHide, visible);
|
||||
},
|
||||
loadMoreData() {
|
||||
this.isLoadingNewData = true;
|
||||
doLoadMoreFiles(this.link, this.diffEnd, () => {
|
||||
this.isLoadingNewData = false;
|
||||
const {pageData} = window.config;
|
||||
this.diffEnd = pageData.diffFileInfo.diffEnd;
|
||||
});
|
||||
loadMoreFiles(this.store.linkLoadMore);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
<script>
|
||||
import {SvgIcon} from '../svg.js';
|
||||
import {DiffTreeStore} from '../modules/stores.js';
|
||||
import {diffTreeStore} from '../modules/stores.js';
|
||||
|
||||
export default {
|
||||
components: {SvgIcon},
|
||||
@ -56,7 +56,7 @@ export default {
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
store: DiffTreeStore,
|
||||
store: diffTreeStore(),
|
||||
collapsed: false,
|
||||
}),
|
||||
methods: {
|
||||
|
@ -60,14 +60,38 @@
|
||||
|
||||
<div class="action-view-right">
|
||||
<div class="job-info-header">
|
||||
<h3 class="job-info-header-title">
|
||||
{{ currentJob.title }}
|
||||
</h3>
|
||||
<p class="job-info-header-detail">
|
||||
{{ currentJob.detail }}
|
||||
</p>
|
||||
<div class="job-info-header-left">
|
||||
<h3 class="job-info-header-title">
|
||||
{{ currentJob.title }}
|
||||
</h3>
|
||||
<p class="job-info-header-detail">
|
||||
{{ currentJob.detail }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="job-info-header-right">
|
||||
<div class="ui top right pointing dropdown custom jump item" @click.stop="menuVisible = !menuVisible" @keyup.enter="menuVisible = !menuVisible">
|
||||
<button class="ui button button-ghost gt-p-3">
|
||||
<SvgIcon name="octicon-gear" :size="18"/>
|
||||
</button>
|
||||
<div class="menu transition action-job-menu" :class="{visible: menuVisible}" v-if="menuVisible" v-cloak>
|
||||
<a class="item" @click="toggleTimeDisplay('seconds')">
|
||||
<i class="icon"><SvgIcon v-show="timeVisible['log-time-seconds']" name="octicon-check"/></i>
|
||||
{{ locale.showLogSeconds }}
|
||||
</a>
|
||||
<a class="item" @click="toggleTimeDisplay('stamp')">
|
||||
<i class="icon"><SvgIcon v-show="timeVisible['log-time-stamp']" name="octicon-check"/></i>
|
||||
{{ locale.showTimeStamps }}
|
||||
</a>
|
||||
<div class="divider"/>
|
||||
<a class="item" @click="toggleFullScreen()">
|
||||
<i class="icon"><SvgIcon v-show="isFullScreen" name="octicon-check"/></i>
|
||||
{{ locale.showFullScreen }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-step-container">
|
||||
<div class="job-step-container" ref="steps">
|
||||
<div class="job-step-section" v-for="(jobStep, i) in currentJob.steps" :key="i">
|
||||
<div class="job-step-summary" @click.stop="toggleStepLogs(i)" :class="currentJobStepsStates[i].expanded ? 'selected' : ''">
|
||||
<!-- If the job is done and the job step log is loaded for the first time, show the loading icon
|
||||
@ -81,7 +105,8 @@
|
||||
<span class="step-summary-duration">{{ jobStep.duration }}</span>
|
||||
</div>
|
||||
|
||||
<!-- the log elements could be a lot, do not use v-if to destroy/reconstruct the DOM -->
|
||||
<!-- the log elements could be a lot, do not use v-if to destroy/reconstruct the DOM,
|
||||
use native DOM elements for "log line" to improve performance, Vue is not suitable for managing so many reactive elements. -->
|
||||
<div class="job-step-logs" ref="logs" v-show="currentJobStepsStates[i].expanded"/>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,6 +120,8 @@ import {SvgIcon} from '../svg.js';
|
||||
import ActionRunStatus from './ActionRunStatus.vue';
|
||||
import {createApp} from 'vue';
|
||||
import AnsiToHTML from 'ansi-to-html';
|
||||
import {toggleElem} from '../utils/dom.js';
|
||||
import {getCurrentLocale} from '../utils.js';
|
||||
|
||||
const {csrfToken} = window.config;
|
||||
|
||||
@ -121,6 +148,12 @@ const sfc = {
|
||||
currentJobStepsStates: [],
|
||||
artifacts: [],
|
||||
onHoverRerunIndex: -1,
|
||||
menuVisible: false,
|
||||
isFullScreen: false,
|
||||
timeVisible: {
|
||||
'log-time-stamp': false,
|
||||
'log-time-seconds': false,
|
||||
},
|
||||
|
||||
// provided by backend
|
||||
run: {
|
||||
@ -173,6 +206,11 @@ const sfc = {
|
||||
// load job data and then auto-reload periodically
|
||||
this.loadJob();
|
||||
this.intervalID = setInterval(this.loadJob, 1000);
|
||||
document.body.addEventListener('click', this.closeDropdown);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
document.body.removeEventListener('click', this.closeDropdown);
|
||||
},
|
||||
|
||||
unmounted() {
|
||||
@ -240,7 +278,7 @@ const sfc = {
|
||||
this.fetchPost(`${this.run.link}/approve`);
|
||||
},
|
||||
|
||||
createLogLine(line) {
|
||||
createLogLine(line, startTime) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('job-log-line');
|
||||
div._jobLogTime = line.timestamp;
|
||||
@ -250,21 +288,35 @@ const sfc = {
|
||||
lineNumber.textContent = line.index;
|
||||
div.append(lineNumber);
|
||||
|
||||
// TODO: Support displaying time optionally
|
||||
// for "Show timestamps"
|
||||
const logTimeStamp = document.createElement('span');
|
||||
logTimeStamp.className = 'log-time-stamp';
|
||||
const date = new Date(parseFloat(line.timestamp * 1000));
|
||||
const timeStamp = date.toLocaleString(getCurrentLocale(), {timeZoneName: 'short'});
|
||||
logTimeStamp.textContent = timeStamp;
|
||||
toggleElem(logTimeStamp, this.timeVisible['log-time-stamp']);
|
||||
// for "Show seconds"
|
||||
const logTimeSeconds = document.createElement('span');
|
||||
logTimeSeconds.className = 'log-time-seconds';
|
||||
const seconds = Math.floor(parseFloat(line.timestamp) - parseFloat(startTime));
|
||||
logTimeSeconds.textContent = `${seconds}s`;
|
||||
toggleElem(logTimeSeconds, this.timeVisible['log-time-seconds']);
|
||||
|
||||
const logMessage = document.createElement('div');
|
||||
const logMessage = document.createElement('span');
|
||||
logMessage.className = 'log-msg';
|
||||
logMessage.innerHTML = ansiLogToHTML(line.message);
|
||||
div.append(logTimeStamp);
|
||||
div.append(logMessage);
|
||||
div.append(logTimeSeconds);
|
||||
|
||||
return div;
|
||||
},
|
||||
|
||||
appendLogs(stepIndex, logLines) {
|
||||
appendLogs(stepIndex, logLines, startTime) {
|
||||
for (const line of logLines) {
|
||||
// TODO: group support: ##[group]GroupTitle , ##[endgroup]
|
||||
const el = this.getLogsContainer(stepIndex);
|
||||
el.append(this.createLogLine(line));
|
||||
el.append(this.createLogLine(line, startTime));
|
||||
}
|
||||
},
|
||||
|
||||
@ -309,7 +361,7 @@ const sfc = {
|
||||
for (const logs of response.logs.stepsLog) {
|
||||
// save the cursor, it will be passed to backend next time
|
||||
this.currentJobStepsStates[logs.step].cursor = logs.cursor;
|
||||
this.appendLogs(logs.step, logs.lines);
|
||||
this.appendLogs(logs.step, logs.lines, logs.started);
|
||||
}
|
||||
|
||||
if (this.run.done && this.intervalID) {
|
||||
@ -335,6 +387,46 @@ const sfc = {
|
||||
|
||||
isDone(status) {
|
||||
return ['success', 'skipped', 'failure', 'cancelled'].includes(status);
|
||||
},
|
||||
|
||||
closeDropdown() {
|
||||
if (this.menuVisible) this.menuVisible = false;
|
||||
},
|
||||
|
||||
// show at most one of log seconds and timestamp (can be both invisible)
|
||||
toggleTimeDisplay(type) {
|
||||
const toToggleTypes = [];
|
||||
const other = type === 'seconds' ? 'stamp' : 'seconds';
|
||||
this.timeVisible[`log-time-${type}`] = !this.timeVisible[`log-time-${type}`];
|
||||
toToggleTypes.push(type);
|
||||
if (this.timeVisible[`log-time-${type}`] && this.timeVisible[`log-time-${other}`]) {
|
||||
this.timeVisible[`log-time-${other}`] = false;
|
||||
toToggleTypes.push(other);
|
||||
}
|
||||
for (const toToggle of toToggleTypes) {
|
||||
for (const el of this.$refs.steps.querySelectorAll(`.log-time-${toToggle}`)) {
|
||||
toggleElem(el, this.timeVisible[`log-time-${toToggle}`]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggleFullScreen() {
|
||||
this.isFullScreen = !this.isFullScreen;
|
||||
const fullScreenEl = document.querySelector('.action-view-right');
|
||||
const outerEl = document.querySelector('.full.height');
|
||||
const actionBodyEl = document.querySelector('.action-view-body');
|
||||
const headerEl = document.querySelector('.ui.main.menu');
|
||||
const contentEl = document.querySelector('.page-content.repository');
|
||||
const footerEl = document.querySelector('.page-footer');
|
||||
toggleElem(headerEl, !this.isFullScreen);
|
||||
toggleElem(contentEl, !this.isFullScreen);
|
||||
toggleElem(footerEl, !this.isFullScreen);
|
||||
// move .action-view-right to new parent
|
||||
if (this.isFullScreen) {
|
||||
outerEl.append(fullScreenEl);
|
||||
} else {
|
||||
actionBodyEl.append(fullScreenEl);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -360,6 +452,9 @@ export function initRepositoryActionView() {
|
||||
rerun: el.getAttribute('data-locale-rerun'),
|
||||
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
|
||||
rerun_all: el.getAttribute('data-locale-rerun-all'),
|
||||
showTimeStamps: el.getAttribute('data-locale-show-timestamps'),
|
||||
showLogSeconds: el.getAttribute('data-locale-show-log-seconds'),
|
||||
showFullScreen: el.getAttribute('data-locale-show-full-screen'),
|
||||
status: {
|
||||
unknown: el.getAttribute('data-locale-status-unknown'),
|
||||
waiting: el.getAttribute('data-locale-status-waiting'),
|
||||
@ -369,7 +464,7 @@ export function initRepositoryActionView() {
|
||||
cancelled: el.getAttribute('data-locale-status-cancelled'),
|
||||
skipped: el.getAttribute('data-locale-status-skipped'),
|
||||
blocked: el.getAttribute('data-locale-status-blocked'),
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
view.mount(el);
|
||||
@ -567,21 +662,95 @@ export function ansiLogToHTML(line) {
|
||||
|
||||
.action-view-right {
|
||||
flex: 1;
|
||||
color: var(--color-secondary-dark-3);
|
||||
color: var(--color-console-fg-subtle);
|
||||
max-height: 100%;
|
||||
width: 70%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* begin fomantic button overrides */
|
||||
|
||||
.action-view-right .ui.button,
|
||||
.action-view-right .ui.button:focus {
|
||||
background: transparent;
|
||||
color: var(--color-console-fg-subtle);
|
||||
}
|
||||
|
||||
.action-view-right .ui.button:hover {
|
||||
background: var(--color-console-hover-bg);
|
||||
color: var(--color-console-fg);
|
||||
}
|
||||
|
||||
.action-view-right .ui.button:active {
|
||||
background: var(--color-console-active-bg);
|
||||
color: var(--color-console-fg);
|
||||
}
|
||||
|
||||
/* end fomantic button overrides */
|
||||
|
||||
/* begin fomantic dropdown menu overrides */
|
||||
|
||||
.action-view-right .ui.dropdown .menu {
|
||||
background: var(--color-console-menu-bg);
|
||||
border-color: var(--color-console-menu-border);
|
||||
}
|
||||
|
||||
.action-view-right .ui.dropdown .menu > .item {
|
||||
color: var(--color-console-fg);
|
||||
}
|
||||
|
||||
.action-view-right .ui.dropdown .menu > .item:hover {
|
||||
color: var(--color-console-fg);
|
||||
background: var(--color-console-hover-bg);
|
||||
}
|
||||
|
||||
.action-view-right .ui.dropdown .menu > .item:active {
|
||||
color: var(--color-console-fg);
|
||||
background: var(--color-console-active-bg);
|
||||
}
|
||||
|
||||
.action-view-right .ui.dropdown .menu > .divider {
|
||||
border-top-color: var(--color-console-menu-border);
|
||||
}
|
||||
|
||||
.action-view-right .ui.pointing.dropdown > .menu:not(.hidden)::after {
|
||||
background: var(--color-console-menu-bg);
|
||||
box-shadow: -1px -1px 0 0 var(--color-console-menu-border);
|
||||
}
|
||||
|
||||
/* end fomantic dropdown menu overrides */
|
||||
|
||||
/* selectors here are intentionally exact to only match fullscreen */
|
||||
|
||||
.full.height > .action-view-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.full.height > .action-view-right > .job-info-header {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.full.height > .action-view-right > .job-step-container {
|
||||
height: calc(100% - 60px);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.job-info-header {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid var(--color-console-border);
|
||||
background-color: var(--color-console-bg);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
height: 60px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.job-info-header .job-info-header-title {
|
||||
@ -591,7 +760,7 @@ export function ansiLogToHTML(line) {
|
||||
}
|
||||
|
||||
.job-info-header .job-info-header-detail {
|
||||
color: var(--color-secondary-dark-3);
|
||||
color: var(--color-console-fg-subtle);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -676,14 +845,20 @@ export function ansiLogToHTML(line) {
|
||||
background-color: var(--color-console-hover-bg);
|
||||
}
|
||||
|
||||
.job-step-section .job-step-logs .job-log-line .line-num {
|
||||
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
|
||||
.job-log-line .line-num, .log-time-seconds {
|
||||
width: 48px;
|
||||
color: var(--color-grey-light);
|
||||
text-align: right;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.job-step-section .job-step-logs .job-log-line .log-time {
|
||||
.log-time-seconds {
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.job-log-line .log-time,
|
||||
.log-time-stamp {
|
||||
color: var(--color-grey-light);
|
||||
margin-left: 10px;
|
||||
white-space: nowrap;
|
||||
|
@ -5,7 +5,7 @@ import {initDiffFileTree} from './repo-diff-filetree.js';
|
||||
import {validateTextareaNonEmpty} from './comp/ComboMarkdownEditor.js';
|
||||
import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndCollapseFilesButton} from './pull-view-file.js';
|
||||
|
||||
const {csrfToken} = window.config;
|
||||
const {csrfToken, pageData} = window.config;
|
||||
|
||||
function initRepoDiffReviewButton() {
|
||||
const $reviewBox = $('#review-box');
|
||||
@ -119,37 +119,29 @@ function onShowMoreFiles() {
|
||||
countAndUpdateViewedFiles();
|
||||
}
|
||||
|
||||
export function doLoadMoreFiles(link, diffEnd, callback) {
|
||||
const url = `${link}?skip-to=${diffEnd}&file-only=true`;
|
||||
loadMoreFiles(url, callback);
|
||||
}
|
||||
|
||||
function loadMoreFiles(url, callback) {
|
||||
export function loadMoreFiles(url) {
|
||||
const $target = $('a#diff-show-more-files');
|
||||
if ($target.hasClass('disabled')) {
|
||||
callback();
|
||||
if ($target.hasClass('disabled') || pageData.diffFileInfo.isLoadingNewData) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageData.diffFileInfo.isLoadingNewData = true;
|
||||
$target.addClass('disabled');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
}).done((resp) => {
|
||||
if (!resp) {
|
||||
$target.removeClass('disabled');
|
||||
callback(resp);
|
||||
return;
|
||||
}
|
||||
$('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children());
|
||||
// By simply rerunning the script we add the new data to our existing
|
||||
// pagedata object. this triggers vue and the filetree and filelist will
|
||||
// render the new elements.
|
||||
$('body').append($(resp).find('script#diff-data-script'));
|
||||
const $resp = $(resp);
|
||||
// the response is a full HTML page, we need to extract the relevant contents:
|
||||
// 1. append the newly loaded file list items to the existing list
|
||||
$('#diff-incomplete').replaceWith($resp.find('#diff-file-boxes').children());
|
||||
// 2. re-execute the script to append the newly loaded items to the JS variables to refresh the DiffFileTree
|
||||
$('body').append($resp.find('script#diff-data-script'));
|
||||
|
||||
onShowMoreFiles();
|
||||
callback(resp);
|
||||
}).fail(() => {
|
||||
}).always(() => {
|
||||
$target.removeClass('disabled');
|
||||
callback();
|
||||
pageData.diffFileInfo.isLoadingNewData = false;
|
||||
});
|
||||
}
|
||||
|
||||
@ -158,7 +150,8 @@ function initRepoDiffShowMore() {
|
||||
e.preventDefault();
|
||||
|
||||
const $target = $(e.target);
|
||||
loadMoreFiles($target.data('href'), () => {});
|
||||
const linkLoadMore = $target.attr('data-href');
|
||||
loadMoreFiles(linkLoadMore);
|
||||
});
|
||||
|
||||
$(document).on('click', 'a.diff-load-button', (e) => {
|
||||
|
@ -1,57 +0,0 @@
|
||||
import {joinPaths, parseUrl} from '../utils.js';
|
||||
|
||||
const {useServiceWorker, assetUrlPrefix, assetVersionEncoded} = window.config;
|
||||
const cachePrefix = 'static-cache-v'; // actual version is set in the service worker script
|
||||
const workerUrl = `${joinPaths(assetUrlPrefix, 'serviceworker.js')}?v=${assetVersionEncoded}`;
|
||||
|
||||
async function unregisterAll() {
|
||||
for (const registration of await navigator.serviceWorker.getRegistrations()) {
|
||||
if (registration.active) await registration.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
async function unregisterOtherWorkers() {
|
||||
for (const registration of await navigator.serviceWorker.getRegistrations()) {
|
||||
const scriptPath = parseUrl(registration.active?.scriptURL || '').pathname;
|
||||
const workerPath = parseUrl(workerUrl).pathname;
|
||||
if (scriptPath !== workerPath) await registration.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
async function invalidateCache() {
|
||||
for (const key of await caches.keys()) {
|
||||
if (key.startsWith(cachePrefix)) caches.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkCacheValidity() {
|
||||
const cacheKey = assetVersionEncoded;
|
||||
const storedCacheKey = localStorage.getItem('staticCacheKey');
|
||||
|
||||
// invalidate cache if it belongs to a different gitea version
|
||||
if (cacheKey && storedCacheKey !== cacheKey) {
|
||||
await invalidateCache();
|
||||
localStorage.setItem('staticCacheKey', cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
export async function initServiceWorker() {
|
||||
if (!('serviceWorker' in navigator)) return;
|
||||
|
||||
if (useServiceWorker) {
|
||||
// unregister all service workers where scriptURL does not match the current one
|
||||
await unregisterOtherWorkers();
|
||||
try {
|
||||
// the spec strictly requires it to be same-origin so the AssetUrlPrefix should contain AppSubUrl
|
||||
await checkCacheValidity();
|
||||
await navigator.serviceWorker.register(workerUrl);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
await invalidateCache();
|
||||
await unregisterAll();
|
||||
}
|
||||
} else {
|
||||
await invalidateCache();
|
||||
await unregisterAll();
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ import {initHeatmap} from './features/heatmap.js';
|
||||
import {initImageDiff} from './features/imagediff.js';
|
||||
import {initRepoMigration} from './features/repo-migration.js';
|
||||
import {initRepoProject} from './features/repo-projects.js';
|
||||
import {initServiceWorker} from './features/serviceworker.js';
|
||||
import {initTableSort} from './features/tablesort.js';
|
||||
import {initAdminUserListSearchForm} from './features/admin/users.js';
|
||||
import {initAdminConfigs} from './features/admin/config.js';
|
||||
@ -116,7 +115,6 @@ onDomReady(() => {
|
||||
initImageDiff();
|
||||
initMarkupAnchors();
|
||||
initMarkupContent();
|
||||
initServiceWorker();
|
||||
initSshKeyFormParser();
|
||||
initStopwatch();
|
||||
initTableSort();
|
||||
|
@ -1,5 +1,10 @@
|
||||
import {reactive} from 'vue';
|
||||
|
||||
export const DiffTreeStore = reactive({
|
||||
selectedItem: '',
|
||||
});
|
||||
let diffTreeStoreReactive;
|
||||
export function diffTreeStore() {
|
||||
if (!diffTreeStoreReactive) {
|
||||
diffTreeStoreReactive = reactive(window.config.pageData.diffFileInfo);
|
||||
window.config.pageData.diffFileInfo = diffTreeStoreReactive;
|
||||
}
|
||||
return diffTreeStoreReactive;
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
import {registerRoute} from 'workbox-routing';
|
||||
import {StaleWhileRevalidate} from 'workbox-strategies';
|
||||
|
||||
const cacheName = 'static-cache-v2';
|
||||
|
||||
// disable workbox debug logging in development, remove when debugging the service worker
|
||||
self.__WB_DISABLE_DEV_LOGS = true;
|
||||
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/RequestDestination for possible values
|
||||
const cachedDestinations = new Set([
|
||||
'font',
|
||||
'manifest',
|
||||
'paintworklet',
|
||||
'script',
|
||||
'sharedworker',
|
||||
'style',
|
||||
'worker',
|
||||
]);
|
||||
|
||||
registerRoute(
|
||||
({request}) => cachedDestinations.has(request.destination),
|
||||
new StaleWhileRevalidate({cacheName}),
|
||||
);
|
@ -26,6 +26,7 @@ import octiconEye from '../../public/img/svg/octicon-eye.svg';
|
||||
import octiconFile from '../../public/img/svg/octicon-file.svg';
|
||||
import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg';
|
||||
import octiconFilter from '../../public/img/svg/octicon-filter.svg';
|
||||
import octiconGear from '../../public/img/svg/octicon-gear.svg';
|
||||
import octiconGitBranch from '../../public/img/svg/octicon-git-branch.svg';
|
||||
import octiconGitMerge from '../../public/img/svg/octicon-git-merge.svg';
|
||||
import octiconGitPullRequest from '../../public/img/svg/octicon-git-pull-request.svg';
|
||||
@ -94,6 +95,7 @@ const svgs = {
|
||||
'octicon-file': octiconFile,
|
||||
'octicon-file-directory-fill': octiconFileDirectoryFill,
|
||||
'octicon-filter': octiconFilter,
|
||||
'octicon-gear': octiconGear,
|
||||
'octicon-git-branch': octiconGitBranch,
|
||||
'octicon-git-merge': octiconGitMerge,
|
||||
'octicon-git-pull-request': octiconGitPullRequest,
|
||||
@ -132,7 +134,7 @@ const svgs = {
|
||||
'octicon-tag': octiconTag,
|
||||
'octicon-triangle-down': octiconTriangleDown,
|
||||
'octicon-x': octiconX,
|
||||
'octicon-x-circle-fill': octiconXCircleFill
|
||||
'octicon-x-circle-fill': octiconXCircleFill,
|
||||
};
|
||||
|
||||
// TODO: use a more general approach to access SVG icons.
|
||||
|
@ -60,7 +60,7 @@ export function parseUrl(str) {
|
||||
}
|
||||
|
||||
// return current locale chosen by user
|
||||
function getCurrentLocale() {
|
||||
export function getCurrentLocale() {
|
||||
return document.documentElement.lang;
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,6 @@ export default {
|
||||
fileURLToPath(new URL('web_src/js/standalone/swagger.js', import.meta.url)),
|
||||
fileURLToPath(new URL('web_src/css/standalone/swagger.css', import.meta.url)),
|
||||
],
|
||||
serviceworker: [
|
||||
fileURLToPath(new URL('web_src/js/serviceworker.js', import.meta.url)),
|
||||
],
|
||||
'eventsource.sharedworker': [
|
||||
fileURLToPath(new URL('web_src/js/features/eventsource.sharedworker.js', import.meta.url)),
|
||||
],
|
||||
@ -73,11 +70,7 @@ export default {
|
||||
devtool: false,
|
||||
output: {
|
||||
path: fileURLToPath(new URL('public', import.meta.url)),
|
||||
filename: ({chunk}) => {
|
||||
// serviceworker can only manage assets below it's script's directory so
|
||||
// we have to put it in / instead of /js/
|
||||
return chunk.name === 'serviceworker' ? '[name].js' : 'js/[name].js';
|
||||
},
|
||||
filename: () => 'js/[name].js',
|
||||
chunkFilename: ({chunk}) => {
|
||||
const language = (/monaco.*languages?_.+?_(.+?)_/.exec(chunk.id) || [])[1];
|
||||
return `js/${language ? `monaco-language-${language.toLowerCase()}` : `[name]`}.[contenthash:8].js`;
|
||||
|
Loading…
x
Reference in New Issue
Block a user