diff --git a/.drone.yml b/.drone.yml index 95b92ffaa15..1fd42fa4ecc 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,5 +1,5 @@ workspace: - base: /srv/app + base: /go path: src/code.gitea.io/gitea clone: @@ -56,21 +56,18 @@ pipeline: event: [ push, tag, pull_request ] build-without-gcc: - image: webhippie/golang:1.8 + image: golang:1.8 pull: true - environment: - GOPATH: /srv/app commands: - go build -o gitea_no_gcc # test if build succeeds without the sqlite tag when: event: [ push, tag, pull_request ] build: - image: webhippie/golang:edge + image: golang:1.10 pull: true environment: TAGS: bindata sqlite - GOPATH: /srv/app commands: - make clean - make generate @@ -85,12 +82,11 @@ pipeline: event: [ push, tag, pull_request ] test: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata sqlite - GOPATH: /srv/app commands: - make unit-test-coverage when: @@ -98,12 +94,11 @@ pipeline: branch: [ master ] test: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata sqlite - GOPATH: /srv/app commands: - make test when: @@ -111,12 +106,11 @@ pipeline: branch: [ release/* ] test: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata - GOPATH: /srv/app commands: - make test when: @@ -124,60 +118,64 @@ pipeline: # Commented until db locking have been resolved! # test-sqlite: - # image: webhippie/golang:edge + # image: golang:1.10 # pull: true # group: test # environment: # TAGS: bindata - # GOPATH: /srv/app # commands: # - make test-sqlite # when: # event: [ push, tag, pull_request ] test-mysql: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata - GOPATH: /srv/app + TEST_LDAP: "1" commands: + - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - apt-get install -y git-lfs - make integration-test-coverage when: event: [ push, pull_request ] branch: [ master ] test-mysql: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata - GOPATH: /srv/app + TEST_LDAP: "1" commands: + - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - apt-get install -y git-lfs - make test-mysql when: event: [ tag ] test-pgsql: - image: webhippie/golang:edge + image: golang:1.10 pull: true group: test environment: TAGS: bindata - GOPATH: /srv/app + TEST_LDAP: "1" commands: + - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash + - apt-get install -y git-lfs - make test-pgsql when: event: [ push, tag, pull_request ] generate-coverage: - image: webhippie/golang:edge + image: golang:1.10 pull: true environment: TAGS: bindata - GOPATH: /srv/app commands: - make coverage when: @@ -198,7 +196,6 @@ pipeline: pull: true environment: TAGS: bindata sqlite - GOPATH: /srv/app commands: - make release when: @@ -342,3 +339,8 @@ services: - POSTGRES_DB=test when: event: [ push, tag, pull_request ] + + ldap: + image: gitea/test-openldap:latest + when: + event: [ push, tag, pull_request ] diff --git a/.gitignore b/.gitignore index 94fbb8adc7d..9a5f01bb94c 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,13 @@ coverage.all /integrations/mysql.ini /integrations/pgsql.ini /node_modules + + +# Snapcraft +snap/.snapcraft/ +parts/ +stage/ +prime/ +*.snap +*.snap-build +*_source.tar.bz2 diff --git a/Makefile b/Makefile index f79df2b4b3d..9adba6a98a6 100644 --- a/Makefile +++ b/Makefile @@ -292,7 +292,7 @@ stylesheets-check: generate-stylesheets .PHONY: generate-stylesheets generate-stylesheets: - node_modules/.bin/lessc --no-ie-compat --clean-css public/less/index.less public/css/index.css + node_modules/.bin/lessc --clean-css public/less/index.less public/css/index.css .PHONY: swagger-ui swagger-ui: diff --git a/README.md b/README.md index 566a4f17800..bd84a888df4 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,11 @@ [![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) [![Join the Discord chat at https://discord.gg/NsatcWJ](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ) -[![Join the Matrix chat at https://matrix.to/#/#gitea:matrix.org](https://img.shields.io/badge/matrix-%23gitea%3Amatrix.org-7bc9a4.svg)](https://matrix.to/#/#gitea:matrix.org) [![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") [![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea) [![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) -[![Release](https://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest) +[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) [![Help Contribute to Open Source](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) @@ -63,7 +62,6 @@ For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.io/en-us/). If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/NsatcWJ), -[Matrix room](https://matrix.to/#/#gitea:matrix.org), or [forum](https://discourse.gitea.io/)! ## Authors @@ -72,6 +70,27 @@ or [forum](https://discourse.gitea.io/)! * [Contributors](https://github.com/go-gitea/gitea/graphs/contributors) * [Translators](options/locale/TRANSLATORS) +## Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/gitea#backer)] + + + +## Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/gitea#sponsor)] + + + + + + + + + + + + ## License This project is licensed under the MIT License. diff --git a/README_ZH.md b/README_ZH.md index db9e17476e4..80533262b14 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -8,7 +8,7 @@ [![Coverage Status](https://coverage.gitea.io/badges/go-gitea/gitea/coverage.svg)](https://coverage.gitea.io/go-gitea/gitea) [![Go Report Card](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea) [![GoDoc](https://godoc.org/code.gitea.io/gitea?status.svg)](https://godoc.org/code.gitea.io/gitea) -[![Release](https://github-release-version.herokuapp.com/github/go-gitea/gitea/release.svg?style=flat)](https://github.com/go-gitea/gitea/releases/latest) +[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest) [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea) | | | | diff --git a/contrib/systemd/gitea.service b/contrib/systemd/gitea.service index 7c09fa3213b..8c627e7b5c3 100644 --- a/contrib/systemd/gitea.service +++ b/contrib/systemd/gitea.service @@ -22,6 +22,11 @@ WorkingDirectory=/home/git/gitea ExecStart=/home/git/gitea/gitea web Restart=always Environment=USER=git HOME=/home/git +# If you want to bind Gitea to a port below 1024 uncomment +# the two values below +### +#CapabilityBoundingSet=CAP_NET_BIND_SERVICE +#AmbientCapabilities=CAP_NET_BIND_SERVICE [Install] WantedBy=multi-user.target diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index e2af3c70811..68f144c089b 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -2,7 +2,9 @@ ; Copy required sections to your own app.ini (default is custom/conf/app.ini) ; and modify as needed. -; App name that shows on every page title +; see https://docs.gitea.io/en-us/config-cheat-sheet/ for additional documentation. + +; App name that shows in every page title APP_NAME = Gitea: Git with a cup of tea ; Change it if you run locally RUN_USER = git @@ -16,28 +18,28 @@ SCRIPT_TYPE = bash ANSI_CHARSET = ; Force every new repository to be private FORCE_PRIVATE = false -; Default private when create a new repository, could be: last, private, public. Default is last which means last user repo visiblity. +; Default privacy setting when creating a new repository, allowed values: last, private, public. Default is last which means the last setting used. DEFAULT_PRIVATE = last -; Global maximum creation limit of repository per user, -1 means no limit +; Global limit of repositories per user, applied at creation time. -1 means no limit MAX_CREATION_LIMIT = -1 ; Mirror sync queue length, increase if mirror syncing starts hanging MIRROR_QUEUE_LENGTH = 1000 ; Patch test queue length, increase if pull request patch testing starts hanging PULL_REQUEST_QUEUE_LENGTH = 1000 ; Preferred Licenses to place at the top of the List -; Name must match file name in conf/license or custom/conf/license +; The name here must match the filename in conf/license or custom/conf/license PREFERRED_LICENSES = Apache License 2.0,MIT License -; Disable ability to interact with repositories by HTTP protocol +; Disable the ability to interact with repositories using the HTTP protocol DISABLE_HTTP_GIT = false ; Force ssh:// clone url instead of scp-style uri when default SSH port is used USE_COMPAT_SSH_URI = false [repository.editor] -; List of file extensions that should have line wraps in the CodeMirror editor -; Separate extensions with a comma. To line wrap files w/o extension, just put a comma +; List of file extensions for which lines should be wrapped in the CodeMirror editor +; Separate extensions with a comma. To line wrap files without an extension, just put a comma LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd, ; Valid file modes that have a preview API associated with them, such as api/v1/markdown -; Separate values by commas. Preview tab in edit mode won't show if the file extension doesn't match +; Separate the values by commas. The preview tab in edit mode won't be displayed if the file extension doesn't match PREVIEWABLE_FILE_MODES = markdown [repository.local] @@ -53,39 +55,39 @@ ENABLED = true TEMP_PATH = data/tmp/uploads ; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type ALLOWED_TYPES = -; Max size of each file in MB. Defaults to 3MB +; Max size of each file in megabytes. Defaults to 3MB FILE_MAX_SIZE = 3 ; Max number of files per upload. Defaults to 5 MAX_FILES = 5 [ui] -; Number of repositories that are showed in one explore page +; Number of repositories that are displayed on one explore page EXPLORE_PAGING_NUM = 20 -; Number of issues that are showed in one page +; Number of issues that are displayed on one page ISSUE_PAGING_NUM = 10 -; Number of maximum commits showed in one activity feed +; Number of maximum commits displayed in one activity feed FEED_MAX_COMMIT_NUM = 5 ; Value of `theme-color` meta tag, used by Android >= 5.0 ; An invalid color like "none" or "disable" will have the default style ; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android THEME_COLOR_META_TAG = `#6cc644` -; Max size of files to be displayed (defaults is 8MiB) +; Max size of files to be displayed (default is 8MiB) MAX_DISPLAY_FILE_SIZE = 8388608 -; Whether show the user email in the Explore Users page +; Whether the email of the user should be shown in the Explore Users page SHOW_USER_EMAIL = true [ui.admin] -; Number of users that are showed in one page +; Number of users that are displayed on one page USER_PAGING_NUM = 50 -; Number of repos that are showed in one page +; Number of repos that are displayed on one page REPO_PAGING_NUM = 50 -; Number of notices that are showed in one page +; Number of notices that are displayed on in one page NOTICE_PAGING_NUM = 25 -; Number of organization that are showed in one page +; Number of organizations that are displayed on one page ORG_PAGING_NUM = 50 [ui.user] -; Number of repos that are showed in one page +; Number of repos that are displayed on one page REPO_PAGING_NUM = 15 [ui.meta] @@ -100,19 +102,19 @@ ENABLE_HARD_LINE_BREAK = false ; for example git,magnet CUSTOM_URL_SCHEMES = ; List of file extensions that should be rendered/edited as Markdown -; Separate extensions with a comma. To render files w/o extension as markdown, just put a comma +; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd [server] -; Listen protocol. One of 'http', 'https', 'unix' or 'fcgi'. +; The protocol the server listens on. One of 'http', 'https', 'unix' or 'fcgi'. PROTOCOL = http DOMAIN = localhost ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ -; Listen address. Either a IPv4/IPv6 address or the path to a unix socket. +; The address to listen on. Either a IPv4/IPv6 address or the path to a unix socket. HTTP_ADDR = 0.0.0.0 HTTP_PORT = 3000 ; If REDIRECT_OTHER_PORT is true, and PROTOCOL is set to https an http server -; will be started on PORT_TO_REDIRECT and redirect request to the main +; will be started on PORT_TO_REDIRECT and it will redirect plain, non-secure http requests to the main ; ROOT_URL. Defaults are false for REDIRECT_OTHER_PORT and 80 for ; PORT_TO_REDIRECT. REDIRECT_OTHER_PORT = false @@ -125,33 +127,33 @@ UNIX_SOCKET_PERMISSION = 666 LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ ; Disable SSH feature when not available DISABLE_SSH = false -; Whether use builtin SSH server or not. +; Whether to use the builtin SSH server or not. START_SSH_SERVER = false -; Username to use for builtin SSH server. If blank, then it is the value of RUN_USER. +; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER. BUILTIN_SSH_SERVER_USER = ; Domain name to be exposed in clone URL SSH_DOMAIN = %(DOMAIN)s -; Network interface builtin SSH server listens on +; THe network interface the builtin SSH server should listen on SSH_LISTEN_HOST = ; Port number to be exposed in clone URL SSH_PORT = 22 -; Port number builtin SSH server listens on +; The port number the builtin SSH server should listen on SSH_LISTEN_PORT = %(SSH_PORT)s ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. SSH_ROOT_PATH = -; For built-in SSH server only, choose the ciphers to support for SSH connections, +; For the built-in SSH server, choose the ciphers to support for SSH connections, ; for system SSH this setting has no effect SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 -; For built-in SSH server only, choose the key exchange algorithms to support for SSH connections, +; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections, ; for system SSH this setting has no effect SSH_SERVER_KEY_EXCHANGES = diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, curve25519-sha256@libssh.org -; For built-in SSH server only, choose the MACs to support for SSH connections, +; For the built-in SSH server, choose the MACs to support for SSH connections, ; for system SSH this setting has no effect SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1, hmac-sha1-96 -; Directory to create temporary files when test public key using ssh-keygen, -; default is system temporary directory. +; Directory to create temporary files in when testing public keys using ssh-keygen, +; default is the system temporary directory. SSH_KEY_TEST_PATH = -; Path to ssh-keygen, default is 'ssh-keygen' and let shell find out which one to call. +; Path to ssh-keygen, default is 'ssh-keygen' which means the shell is responsible for finding out which one to call. SSH_KEYGEN_PATH = ssh-keygen ; Enable SSH Authorized Key Backup when rewriting all keys, default is true SSH_BACKUP_AUTHORIZED_KEYS = true @@ -171,7 +173,7 @@ DISABLE_ROUTER_LOG = false ; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes CERT_FILE = custom/https/cert.pem KEY_FILE = custom/https/key.pem -; Upper level of template and static file path +; Root directory containing templates and static files. ; default is the path where Gitea is executed STATIC_ROOT_PATH = ; Default path for App data @@ -182,9 +184,9 @@ ENABLE_GZIP = false LANDING_PAGE = home ; Enables git-lfs support. true or false, default is false. LFS_START_SERVER = false -; Where your lfs files put on, default is data/lfs. +; Where your lfs files reside, default is data/lfs. LFS_CONTENT_PATH = data/lfs -; LFS authentication secret, changed this to yourself. +; LFS authentication secret, change this yourself LFS_JWT_SECRET = ; Define allowed algorithms and their minimum key length (use -1 to disable a type) @@ -204,7 +206,7 @@ USER = root PASSWD = ; For "postgres" only, either "disable", "require" or "verify-full" SSL_MODE = disable -; For "sqlite3" and "tidb", use absolute path when you start as service +; For "sqlite3" and "tidb", use absolute path when you start gitea as service PATH = data/gitea.db ; For "sqlite3" only. Query timeout SQLITE_TIMEOUT = 500 @@ -222,7 +224,7 @@ UPDATE_BUFFER_LEN = 20 MAX_FILE_SIZE = 1048576 [admin] -; Disable regular (non-admin) users to create organizations +; Disallow regular (non-admin) users from creating organizations. DISABLE_REGULAR_ORG_CREATION = false [security] @@ -230,13 +232,13 @@ DISABLE_REGULAR_ORG_CREATION = false INSTALL_LOCK = false ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! SECRET_KEY = !#@FDEWREWR&*( -; Auto-login remember days +; How long to remember that an user is logged in before requiring relogin (in days) LOGIN_REMEMBER_DAYS = 7 COOKIE_USERNAME = gitea_awesome COOKIE_REMEMBER_NAME = gitea_incredible ; Reverse proxy authentication header name of user name REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER -; Sets the minimum password length for new Users +; The minimum password length for new Users MIN_PASSWORD_LENGTH = 6 ; True when users are allowed to import local server paths IMPORT_LOCAL_PATHS = false @@ -245,7 +247,7 @@ DISABLE_GIT_HOOKS = false [openid] ; -; OpenID is an open standard and decentralized authentication protocol. +; OpenID is an open, standard and decentralized authentication protocol. ; Your identity is the address of a webpage you provide, which describes ; how to prove you are in control of that page. ; @@ -264,7 +266,7 @@ DISABLE_GIT_HOOKS = false ; Whether to allow signin in via OpenID ENABLE_OPENID_SIGNIN = true ; Whether to allow registering via OpenID -; Do not include to rely on DISABLE_REGISTRATION setting +; Do not include to rely on rhw DISABLE_REGISTRATION setting ;ENABLE_OPENID_SIGNUP = true ; Allowed URI patterns (POSIX regexp). ; Space separated. @@ -280,12 +282,14 @@ BLACKLISTED_URIS = [service] ; Time limit to confirm account/email registration ACTIVE_CODE_LIVE_MINUTES = 180 -; Time limit to confirm forgot password reset process +; Time limit to perform the reset of a forgotten password RESET_PASSWD_CODE_LIVE_MINUTES = 180 -; User need to confirm e-mail for registration +; Whether a new user needs to confirm their email when registering. REGISTER_EMAIL_CONFIRM = false -; Does not allow register and admin create account only +; Disallow registration, only allow admins to create accounts. DISABLE_REGISTRATION = false +; Allow registration only using third part services, it works only when DISABLE_REGISTRATION is false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false ; User must sign in to view anything. REQUIRE_SIGNIN_VIEW = false ; Mail notification @@ -296,10 +300,10 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false ; Enable captcha validation for registration ENABLE_CAPTCHA = true ; Default value for KeepEmailPrivate -; New user will get the value of this setting copied into their profile +; Each new user will get the value of this setting copied into their profile DEFAULT_KEEP_EMAIL_PRIVATE = false ; Default value for AllowCreateOrganization -; New user will have rights set to create organizations depending on this setting +; Every new user will have rights set to create organizations depending on this setting DEFAULT_ALLOW_CREATE_ORGANIZATION = true ; Enable Timetracking ENABLE_TIMETRACKING = true @@ -307,10 +311,10 @@ ENABLE_TIMETRACKING = true ; Repositories will use timetracking by default depending on this setting DEFAULT_ENABLE_TIMETRACKING = true ; Default value for AllowOnlyContributorsToTrackTime -; Only users with write permissions could track time if this is true +; Only users with write permissions can track time if this is true DEFAULT_ALLOW_ONLY_CONTRIBUTORS_TO_TRACK_TIME = true ; Default value for the domain part of the user's email address in the git log -; if he has set KeepEmailPrivate true. The user's email replaced with a +; if he has set KeepEmailPrivate to true. The user's email will be replaced with a ; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS. NO_REPLY_ADDRESS = noreply.example.org @@ -335,9 +339,9 @@ SUBJECT = %(APP_NAME)s ; QQ: smtp.qq.com:465 ; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used. HOST = -; Disable HELO operation when hostname are different. +; Disable HELO operation when hostnames are different. DISABLE_HELO = -; Custom hostname for HELO operation, default is from system. +; Custom hostname for HELO operation, if no value is provided, one is retrieved from system. HELO_HOSTNAME = ; Do not verify the certificate of the server. Only use this for self-signed certificates SKIP_VERIFY = @@ -377,7 +381,7 @@ ITEM_TTL = 16h ; Either "memory", "file", or "redis", default is "memory" PROVIDER = memory ; Provider config options -; memory: not have any config yet +; memory: doesn't have any config yet ; file: session file path, e.g. `data/sessions` ; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180 ; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table` @@ -398,11 +402,11 @@ AVATAR_UPLOAD_PATH = data/avatars ; Chinese users can choose "duoshuo" ; or a custom avatar source, like: http://cn.gravatar.com/avatar/ GRAVATAR_SOURCE = gravatar -; This value will be forced to be true in offline mode. +; This value will always be true in offline mode. DISABLE_GRAVATAR = false ; Federated avatar lookup uses DNS to discover avatar associated ; with emails, see https://www.libravatar.org -; This value will be forced to be false in offline mode or Gravatar is disabled. +; This value will always be false in offline mode or when Gravatar is disabled. ENABLE_FEDERATED_AVATAR = false [attachment] @@ -412,9 +416,9 @@ ENABLE = true PATH = data/attachments ; One or more allowed types, e.g. image/jpeg|image/png ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip -; Max size of each file. Defaults to 32MB +; Max size of each file. Defaults to 4MB MAX_SIZE = 4 -; Max number of files per upload. Defaults to 10 +; Max number of files per upload. Defaults to 5 MAX_FILES = 5 [time] @@ -428,7 +432,7 @@ ROOT_PATH = ; Either "console", "file", "conn", "smtp" or "database", default is "console" ; Use comma to separate multiple modes, e.g. "console, file" MODE = console -; Buffer length of channel, keep it as it is if you don't know what it is. +; Buffer length of the channel, keep it as it is if you don't know what it is. BUFFER_LEN = 10000 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" LEVEL = Trace @@ -442,13 +446,13 @@ LEVEL = LEVEL = ; This enables automated log rotate(switch of following options), default is true LOG_ROTATE = true -; Max line number of single file, default is 1000000 +; Max number of lines in a single file, default is 1000000 MAX_LINES = 1000000 -; Max size shift of single file, default is 28 means 1 << 28, 256MB +; Max size shift of a single file, default is 28 means 1 << 28, 256MB MAX_SIZE_SHIFT = 28 ; Segment log daily, default is true DAILY_ROTATE = true -; Expired days of log file(delete after max days), default is 7 +; delete the log file after n days, default is 7 MAX_DAYS = 7 ; For "conn" mode only @@ -532,9 +536,9 @@ UPDATE_EXISTING = true [git] ; Disables highlight of added and removed changes DISABLE_DIFF_HIGHLIGHT = false -; Max number of lines allowed of a single file in diff view +; Max number of lines allowed in a single file in diff view MAX_GIT_DIFF_LINES = 1000 -; Max number of characters of a line allowed in diff view +; Max number of allowed characters in a line in diff view MAX_GIT_DIFF_LINE_CHARACTERS = 5000 ; Max number of files shown in diff view MAX_GIT_DIFF_FILES = 100 @@ -559,7 +563,7 @@ MIN_INTERVAL = 10m [api] ; Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true. ENABLE_SWAGGER_ENDPOINT = true -; Max number of items will response in a page +; Max number of items in a page MAX_RESPONSE_ITEMS = 50 [i18n] @@ -598,7 +602,7 @@ ko-KR = ko SHOW_FOOTER_BRANDING = false ; Show version information about Gitea and Go in the footer SHOW_FOOTER_VERSION = true -; Show time of template execution in the footer +; Show template execution time in the footer SHOW_FOOTER_TEMPLATE_LOAD_TIME = true [markup.asciidoc] @@ -607,5 +611,5 @@ ENABLED = false FILE_EXTENSIONS = .adoc,.asciidoc ; External command to render all matching extensions RENDER_COMMAND = "asciidoc --out-file=- -" -; Input is not a standard input but a file +; Don't pass the file on STDIN, pass the filename as argument instead. IS_INPUT_FILE = false diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 237016e2d89..2a245ffd006 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -201,8 +201,6 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ## Cache (`cache`) - `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, or `memcache`. - - To use `redis` or `memcache`, be sure to rebuild everything with build tags `redis` or - `memcache`: `go build -tags='redis'`. - `INTERVAL`: **60**: Garbage Collection interval (sec), for memory cache only. - `HOST`: **\**: Connection string for `redis` and `memcache`. - Redis: `network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180` diff --git a/docs/content/doc/features/comparison.en-us.md b/docs/content/doc/features/comparison.en-us.md new file mode 100644 index 00000000000..c2b7b037c3e --- /dev/null +++ b/docs/content/doc/features/comparison.en-us.md @@ -0,0 +1,611 @@ +--- +date: "2018-05-07T13:00:00+02:00" +title: "Gitea compared to other Git hosting options" +slug: "comparison" +weight: 5 +toc: true +draft: false +menu: + sidebar: + parent: "features" + name: "Comparison" + weight: 5 + identifier: "comparison" +--- + +# Gitea compared to other Git hosting options + +To help decide if Gitea is suited for your needs here is how it compares to other Git self hosted options. + +Be warned that we don't regularly check for feature changes in other products so this list can be outdated. If you find anything that needs to be updated in table below please report [issue on Github](https://github.com/go-gitea/gitea/issues). + +_Symbols used in table:_ + +* _✓ - supported_ + +* _⁄ - supported with limited functionality_ + +* _✘ - unsupported_ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureGiteaGogsGitHub EEGitLab CEGitLab EEBitBucket
Open source and free
Issue tracker
Pull/Merge requests
Squash merging
Rebase merging
Pull/Merge request inline comments
Pull/Merge request approval
Merge conflict resolution
Restrict push and merge access to certain users
Markdown support
Issues and pull/merge requests templates
Revert specific commits or a merge request
Labels
Time tracking
Multiple assignees for issues
Related issues
Confidential issues
Comment reactions
Lock Discussion
Batch issue handling
Issue Boards
Create new branches from issues
Commit graph
Web code editor
Branch manager
Create new branches
Repository topics
Repository code search
Global code search
Issue search
Global issue search
Git LFS 2.0
Integrated Git-powered wiki
Static Git-powered pages
Group Milestones
Granular user roles (Code, Issues, Wiki etc)
Cherry-picking changes
GPG Signed Commits
Reject unsigned commits
Verified Committer?
Subgroups: groups within groups
Custom Git Hooks
Repository Activity page
Deploy Tokens
Repository Tokens with write rights
Easy upgrade process
Built-in Container Registry
External git mirroring
AD / LDAP integration
Multiple LDAP / AD server support
LDAP user synchronization
OpenId Connect support?
OAuth 2.0 integration (external authorization)?
Act as OAuth 2.0 provider
Two factor authentication (2FA)
Webhook support
Mattermost/Slack integration
Discord integration
Built-in CI/CD
External CI/CD status display
Multiple database support
Multiple OS support
Low resource usage (RAM/CPU)
diff --git a/docs/content/doc/usage/issue-pull-request-templates.en-us.md b/docs/content/doc/usage/issue-pull-request-templates.en-us.md new file mode 100644 index 00000000000..5eaf0db0c79 --- /dev/null +++ b/docs/content/doc/usage/issue-pull-request-templates.en-us.md @@ -0,0 +1,41 @@ +--- +date: "2018-05-10T16:00:00+02:00" +title: "Usage: Issue and Pull Request templates" +slug: "issue-pull-request-templates" +weight: 15 +toc: true +draft: false +menu: + sidebar: + parent: "usage" + name: "Issue and Pull Request templates" + weight: 15 + identifier: "issue-pull-request-templates" +--- + +# Issue and Pull Request Templates + +For some projects there are a standard list of questions that users need to be asked +for creating an issue, or adding a pull request. Gitea supports adding templates to the +main branch of the repository so that they can autopopulate the form when users are +creating issues, and pull requests. This will cut down on the initial back and forth +of getting some clarifiying details. + +Possible file names for issue templates: + +* ISSUE_TEMPLATE.md +* issue_template.md +* .gitea/ISSUE_TEMPLATE.md +* .gitea/issue_template.md +* .github/ISSUE_TEMPLATE.md +* .github/issue_template.md + + +Possible file names for PR templates: + +* PULL_REQUEST_TEMPLATE.md +* pull_request_template.md +* .gitea/PULL_REQUEST_TEMPLATE.md +* .gitea/pull_request_template.md +* .github/PULL_REQUEST_TEMPLATE.md +* .github/pull_request_template.md diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go new file mode 100644 index 00000000000..df26f95ed01 --- /dev/null +++ b/integrations/auth_ldap_test.go @@ -0,0 +1,194 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "net/http" + "os" + "strings" + "testing" + + "code.gitea.io/gitea/models" + + "github.com/Unknwon/i18n" + "github.com/stretchr/testify/assert" +) + +type ldapUser struct { + UserName string + Password string + FullName string + Email string + OtherEmails []string + IsAdmin bool + SSHKeys []string +} + +var gitLDAPUsers = []ldapUser{ + { + UserName: "professor", + Password: "professor", + FullName: "Hubert Farnsworth", + Email: "professor@planetexpress.com", + OtherEmails: []string{"hubert@planetexpress.com"}, + IsAdmin: true, + }, + { + UserName: "hermes", + Password: "hermes", + FullName: "Conrad Hermes", + Email: "hermes@planetexpress.com", + IsAdmin: true, + }, + { + UserName: "fry", + Password: "fry", + FullName: "Philip Fry", + Email: "fry@planetexpress.com", + }, + { + UserName: "leela", + Password: "leela", + FullName: "Leela Turanga", + Email: "leela@planetexpress.com", + }, + { + UserName: "bender", + Password: "bender", + FullName: "Bender Rodríguez", + Email: "bender@planetexpress.com", + }, +} + +var otherLDAPUsers = []ldapUser{ + { + UserName: "zoidberg", + Password: "zoidberg", + FullName: "John Zoidberg", + Email: "zoidberg@planetexpress.com", + }, + { + UserName: "amy", + Password: "amy", + FullName: "Amy Kroker", + Email: "amy@planetexpress.com", + }, +} + +func skipLDAPTests() bool { + return os.Getenv("TEST_LDAP") != "1" +} + +func getLDAPServerHost() string { + host := os.Getenv("TEST_LDAP_HOST") + if len(host) == 0 { + host = "ldap" + } + return host +} + +func addAuthSourceLDAP(t *testing.T) { + session := loginUser(t, "user1") + csrf := GetCSRF(t, session, "/admin/auths/new") + req := NewRequestWithValues(t, "POST", "/admin/auths/new", map[string]string{ + "_csrf": csrf, + "type": "2", + "name": "ldap", + "host": getLDAPServerHost(), + "port": "389", + "bind_dn": "uid=gitea,ou=service,dc=planetexpress,dc=com", + "bind_password": "password", + "user_base": "ou=people,dc=planetexpress,dc=com", + "filter": "(&(objectClass=inetOrgPerson)(memberOf=cn=git,ou=people,dc=planetexpress,dc=com)(uid=%s))", + "admin_filter": "(memberOf=cn=admin_staff,ou=people,dc=planetexpress,dc=com)", + "attribute_username": "uid", + "attribute_name": "givenName", + "attribute_surname": "sn", + "attribute_mail": "mail", + "is_sync_enabled": "on", + "is_active": "on", + }) + session.MakeRequest(t, req, http.StatusFound) +} + +func TestLDAPUserSignin(t *testing.T) { + if skipLDAPTests() { + t.Skip() + return + } + prepareTestEnv(t) + addAuthSourceLDAP(t) + + u := gitLDAPUsers[0] + + session := loginUserWithPassword(t, u.UserName, u.Password) + req := NewRequest(t, "GET", "/user/settings") + resp := session.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + + assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name")) + assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name")) + assert.Equal(t, u.Email, htmlDoc.GetInputValueByName("email")) +} + +func TestLDAPUserSync(t *testing.T) { + if skipLDAPTests() { + t.Skip() + return + } + prepareTestEnv(t) + addAuthSourceLDAP(t) + models.SyncExternalUsers() + + session := loginUser(t, "user1") + // Check if users exists + for _, u := range gitLDAPUsers { + req := NewRequest(t, "GET", "/admin/users?q="+u.UserName) + resp := session.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + + tr := htmlDoc.doc.Find("table.table tbody tr") + if !assert.True(t, tr.Length() == 1) { + continue + } + tds := tr.Find("td") + if !assert.True(t, tds.Length() > 0) { + continue + } + assert.Equal(t, u.UserName, strings.TrimSpace(tds.Find("td:nth-child(2) a").Text())) + assert.Equal(t, u.Email, strings.TrimSpace(tds.Find("td:nth-child(3) span").Text())) + if u.IsAdmin { + assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-check-square-o")) + } else { + assert.True(t, tds.Find("td:nth-child(5) i").HasClass("fa-square-o")) + } + } + + // Check if no users exist + for _, u := range otherLDAPUsers { + req := NewRequest(t, "GET", "/admin/users?q="+u.UserName) + resp := session.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + + tr := htmlDoc.doc.Find("table.table tbody tr") + assert.True(t, tr.Length() == 0) + } +} + +func TestLDAPUserSigninFailed(t *testing.T) { + if skipLDAPTests() { + t.Skip() + return + } + prepareTestEnv(t) + addAuthSourceLDAP(t) + + u := otherLDAPUsers[0] + + testLoginFailed(t, u.UserName, u.Password, i18n.Tr("en", "form.username_password_incorrect")) +} diff --git a/models/error.go b/models/error.go index 2c7152797fe..19d0259bc41 100644 --- a/models/error.go +++ b/models/error.go @@ -733,6 +733,22 @@ func (err ErrRepoFileAlreadyExist) Error() string { return fmt.Sprintf("repository file already exists [file_name: %s]", err.FileName) } +// ErrUserDoesNotHaveAccessToRepo represets an error where the user doesn't has access to a given repo +type ErrUserDoesNotHaveAccessToRepo struct { + UserID int64 + RepoName string +} + +// IsErrUserDoesNotHaveAccessToRepo checks if an error is a ErrRepoFileAlreadyExist. +func IsErrUserDoesNotHaveAccessToRepo(err error) bool { + _, ok := err.(ErrUserDoesNotHaveAccessToRepo) + return ok +} + +func (err ErrUserDoesNotHaveAccessToRepo) Error() string { + return fmt.Sprintf("user doesn't have acces to repo [user_id: %d, repo_name: %s]", err.UserID, err.RepoName) +} + // __________ .__ // \______ \____________ ____ ____ | |__ // | | _/\_ __ \__ \ / \_/ ___\| | \ diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index ff514e706c9..4de8c4fa7e2 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -3,7 +3,6 @@ repo_id: 1 index: 1 poster_id: 1 - assignee_id: 1 name: issue1 content: content for the first issue is_closed: false @@ -67,7 +66,6 @@ repo_id: 3 index: 1 poster_id: 1 - assignee_id: 1 name: issue6 content: content6 is_closed: false diff --git a/models/fixtures/issue_assignees.yml b/models/fixtures/issue_assignees.yml new file mode 100644 index 00000000000..1be07df7d4a --- /dev/null +++ b/models/fixtures/issue_assignees.yml @@ -0,0 +1,8 @@ +- + id: 1 + assignee_id: 1 + issue_id: 1 +- + id: 2 + assignee_id: 1 + issue_id: 6 diff --git a/models/fixtures/issue_user.yml b/models/fixtures/issue_user.yml index b3f98a71d3d..8039b1e40ff 100644 --- a/models/fixtures/issue_user.yml +++ b/models/fixtures/issue_user.yml @@ -3,7 +3,6 @@ uid: 1 issue_id: 1 is_read: true - is_assigned: true is_mentioned: false - @@ -11,7 +10,6 @@ uid: 2 issue_id: 1 is_read: true - is_assigned: false is_mentioned: false - @@ -19,5 +17,4 @@ uid: 4 issue_id: 1 is_read: false - is_assigned: false is_mentioned: false diff --git a/models/fixtures/login_source.yml b/models/fixtures/login_source.yml new file mode 100644 index 00000000000..ca780a73aa0 --- /dev/null +++ b/models/fixtures/login_source.yml @@ -0,0 +1 @@ +[] # empty diff --git a/models/issue.go b/models/issue.go index 7f83d59842f..ad354cc34ee 100644 --- a/models/issue.go +++ b/models/issue.go @@ -37,7 +37,7 @@ type Issue struct { MilestoneID int64 `xorm:"INDEX"` Milestone *Milestone `xorm:"-"` Priority int - AssigneeID int64 `xorm:"INDEX"` + AssigneeID int64 `xorm:"-"` Assignee *User `xorm:"-"` IsClosed bool `xorm:"INDEX"` IsRead bool `xorm:"-"` @@ -56,6 +56,7 @@ type Issue struct { Comments []*Comment `xorm:"-"` Reactions ReactionList `xorm:"-"` TotalTrackedTime int64 `xorm:"-"` + Assignees []*User `xorm:"-"` } var ( @@ -140,22 +141,6 @@ func (issue *Issue) loadPoster(e Engine) (err error) { return } -func (issue *Issue) loadAssignee(e Engine) (err error) { - if issue.Assignee == nil && issue.AssigneeID > 0 { - issue.Assignee, err = getUserByID(e, issue.AssigneeID) - if err != nil { - issue.AssigneeID = -1 - issue.Assignee = NewGhostUser() - if !IsErrUserNotExist(err) { - return fmt.Errorf("getUserByID.(assignee) [%d]: %v", issue.AssigneeID, err) - } - err = nil - return - } - } - return -} - func (issue *Issue) loadPullRequest(e Engine) (err error) { if issue.IsPull && issue.PullRequest == nil { issue.PullRequest, err = getPullRequestByIssueID(e, issue.ID) @@ -231,7 +216,7 @@ func (issue *Issue) loadAttributes(e Engine) (err error) { } } - if err = issue.loadAssignee(e); err != nil { + if err = issue.loadAssignees(e); err != nil { return } @@ -343,8 +328,11 @@ func (issue *Issue) APIFormat() *api.Issue { if issue.Milestone != nil { apiIssue.Milestone = issue.Milestone.APIFormat() } - if issue.Assignee != nil { - apiIssue.Assignee = issue.Assignee.APIFormat() + if len(issue.Assignees) > 0 { + for _, assignee := range issue.Assignees { + apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat()) + } + apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee` } if issue.IsPull { apiIssue.PullRequest = &api.PullRequestMeta{ @@ -605,19 +593,6 @@ func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) { return sess.Commit() } -// GetAssignee sets the Assignee attribute of this issue. -func (issue *Issue) GetAssignee() (err error) { - if issue.AssigneeID == 0 || issue.Assignee != nil { - return nil - } - - issue.Assignee, err = GetUserByID(issue.AssigneeID) - if IsErrUserNotExist(err) { - return nil - } - return err -} - // ReadBy sets issue to be read by given user. func (issue *Issue) ReadBy(userID int64) error { if err := UpdateIssueUserByRead(userID, issue.ID); err != nil { @@ -823,55 +798,6 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) { return nil } -// ChangeAssignee changes the Assignee field of this issue. -func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) { - var oldAssigneeID = issue.AssigneeID - issue.AssigneeID = assigneeID - if err = UpdateIssueUserByAssignee(issue); err != nil { - return fmt.Errorf("UpdateIssueUserByAssignee: %v", err) - } - - sess := x.NewSession() - defer sess.Close() - - if err = issue.loadRepo(sess); err != nil { - return fmt.Errorf("loadRepo: %v", err) - } - - if _, err = createAssigneeComment(sess, doer, issue.Repo, issue, oldAssigneeID, assigneeID); err != nil { - return fmt.Errorf("createAssigneeComment: %v", err) - } - - issue.Assignee, err = GetUserByID(issue.AssigneeID) - if err != nil && !IsErrUserNotExist(err) { - log.Error(4, "GetUserByID [assignee_id: %v]: %v", issue.AssigneeID, err) - return nil - } - - // Error not nil here means user does not exist, which is remove assignee. - isRemoveAssignee := err != nil - if issue.IsPull { - issue.PullRequest.Issue = issue - apiPullRequest := &api.PullRequestPayload{ - Index: issue.Index, - PullRequest: issue.PullRequest.APIFormat(), - Repository: issue.Repo.APIFormat(AccessModeNone), - Sender: doer.APIFormat(), - } - if isRemoveAssignee { - apiPullRequest.Action = api.HookIssueUnassigned - } else { - apiPullRequest.Action = api.HookIssueAssigned - } - if err := PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest); err != nil { - log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, isRemoveAssignee, err) - return nil - } - } - go HookQueue.Add(issue.RepoID) - return nil -} - // GetTasks returns the amount of tasks in the issues content func (issue *Issue) GetTasks() int { return len(issueTasksPat.FindAllStringIndex(issue.Content, -1)) @@ -887,6 +813,7 @@ type NewIssueOptions struct { Repo *Repository Issue *Issue LabelIDs []int64 + AssigneeIDs []int64 Attachments []string // In UUID format. IsPull bool } @@ -909,14 +836,32 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { } } - if assigneeID := opts.Issue.AssigneeID; assigneeID > 0 { - valid, err := hasAccess(e, assigneeID, opts.Repo, AccessModeWrite) - if err != nil { - return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err) + // Keep the old assignee id thingy for compatibility reasons + if opts.Issue.AssigneeID > 0 { + isAdded := false + // Check if the user has already been passed to issue.AssigneeIDs, if not, add it + for _, aID := range opts.AssigneeIDs { + if aID == opts.Issue.AssigneeID { + isAdded = true + break + } } - if !valid { - opts.Issue.AssigneeID = 0 - opts.Issue.Assignee = nil + + if !isAdded { + opts.AssigneeIDs = append(opts.AssigneeIDs, opts.Issue.AssigneeID) + } + } + + // Check for and validate assignees + if len(opts.AssigneeIDs) > 0 { + for _, assigneeID := range opts.AssigneeIDs { + valid, err := hasAccess(e, assigneeID, opts.Repo, AccessModeWrite) + if err != nil { + return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err) + } + if !valid { + return ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: opts.Repo.Name} + } } } @@ -931,11 +876,10 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { } } - if opts.Issue.AssigneeID > 0 { - if err = opts.Issue.loadRepo(e); err != nil { - return err - } - if _, err = createAssigneeComment(e, doer, opts.Issue.Repo, opts.Issue, -1, opts.Issue.AssigneeID); err != nil { + // Insert the assignees + for _, assigneeID := range opts.AssigneeIDs { + err = opts.Issue.changeAssignee(e, doer, assigneeID) + if err != nil { return err } } @@ -995,7 +939,7 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) { } // NewIssue creates new issue with labels for repository. -func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { +func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []int64, uuids []string) (err error) { sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { @@ -1007,7 +951,11 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) Issue: issue, LabelIDs: labelIDs, Attachments: uuids, + AssigneeIDs: assigneeIDs, }); err != nil { + if IsErrUserDoesNotHaveAccessToRepo(err) { + return err + } return fmt.Errorf("newIssue: %v", err) } @@ -1150,7 +1098,8 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) error { } if opts.AssigneeID > 0 { - sess.And("issue.assignee_id=?", opts.AssigneeID) + sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", opts.AssigneeID) } if opts.PosterID > 0 { @@ -1372,7 +1321,8 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { } if opts.AssigneeID > 0 { - sess.And("issue.assignee_id = ?", opts.AssigneeID) + sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", opts.AssigneeID) } if opts.PosterID > 0 { @@ -1438,13 +1388,15 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { } case FilterModeAssign: stats.OpenCount, err = x.Where(cond).And("is_closed = ?", false). - And("assignee_id = ?", opts.UserID). + Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", opts.UserID). Count(new(Issue)) if err != nil { return nil, err } stats.ClosedCount, err = x.Where(cond).And("is_closed = ?", true). - And("assignee_id = ?", opts.UserID). + Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", opts.UserID). Count(new(Issue)) if err != nil { return nil, err @@ -1466,7 +1418,8 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) { cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed}) stats.AssignCount, err = x.Where(cond). - And("assignee_id = ?", opts.UserID). + Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", opts.UserID). Count(new(Issue)) if err != nil { return nil, err @@ -1505,8 +1458,10 @@ func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen switch filterMode { case FilterModeAssign: - openCountSession.And("assignee_id = ?", uid) - closedCountSession.And("assignee_id = ?", uid) + openCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", uid) + closedCountSession.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). + And("issue_assignees.assignee_id = ?", uid) case FilterModeCreate: openCountSession.And("poster_id = ?", uid) closedCountSession.And("poster_id = ?", uid) diff --git a/models/issue_assignees.go b/models/issue_assignees.go new file mode 100644 index 00000000000..3e68126a6c7 --- /dev/null +++ b/models/issue_assignees.go @@ -0,0 +1,263 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "fmt" + + "code.gitea.io/gitea/modules/log" + + api "code.gitea.io/sdk/gitea" + "github.com/go-xorm/xorm" +) + +// IssueAssignees saves all issue assignees +type IssueAssignees struct { + ID int64 `xorm:"pk autoincr"` + AssigneeID int64 `xorm:"INDEX"` + IssueID int64 `xorm:"INDEX"` +} + +// This loads all assignees of an issue +func (issue *Issue) loadAssignees(e Engine) (err error) { + // Reset maybe preexisting assignees + issue.Assignees = []*User{} + + err = e.Table("`user`"). + Join("INNER", "issue_assignees", "assignee_id = `user`.id"). + Where("issue_assignees.issue_id = ?", issue.ID). + Find(&issue.Assignees) + + if err != nil { + return err + } + + // Check if we have at least one assignee and if yes put it in as `Assignee` + if len(issue.Assignees) > 0 { + issue.Assignee = issue.Assignees[0] + } + + return +} + +// GetAssigneesByIssue returns everyone assigned to that issue +func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) { + err = issue.loadAssignees(x) + if err != nil { + return assignees, err + } + + return issue.Assignees, nil +} + +// IsUserAssignedToIssue returns true when the user is assigned to the issue +func IsUserAssignedToIssue(issue *Issue, user *User) (isAssigned bool, err error) { + isAssigned, err = x.Exist(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID}) + return +} + +// DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array +func DeleteNotPassedAssignee(issue *Issue, doer *User, assignees []*User) (err error) { + var found bool + + for _, assignee := range issue.Assignees { + + found = false + for _, alreadyAssignee := range assignees { + if assignee.ID == alreadyAssignee.ID { + found = true + break + } + } + + if !found { + // This function also does comments and hooks, which is why we call it seperatly instead of directly removing the assignees here + if err := UpdateAssignee(issue, doer, assignee.ID); err != nil { + return err + } + } + } + + return nil +} + +// MakeAssigneeList concats a string with all names of the assignees. Useful for logs. +func MakeAssigneeList(issue *Issue) (assigneeList string, err error) { + err = issue.loadAssignees(x) + if err != nil { + return "", err + } + + for in, assignee := range issue.Assignees { + assigneeList += assignee.Name + + if len(issue.Assignees) > (in + 1) { + assigneeList += ", " + } + } + return +} + +// ClearAssigneeByUserID deletes all assignments of an user +func clearAssigneeByUserID(sess *xorm.Session, userID int64) (err error) { + _, err = sess.Delete(&IssueAssignees{AssigneeID: userID}) + return +} + +// AddAssigneeIfNotAssigned adds an assignee only if he isn't aleady assigned to the issue +func AddAssigneeIfNotAssigned(issue *Issue, doer *User, assigneeID int64) (err error) { + // Check if the user is already assigned + isAssigned, err := IsUserAssignedToIssue(issue, &User{ID: assigneeID}) + if err != nil { + return err + } + + if !isAssigned { + return issue.ChangeAssignee(doer, assigneeID) + } + return nil +} + +// UpdateAssignee deletes or adds an assignee to an issue +func UpdateAssignee(issue *Issue, doer *User, assigneeID int64) (err error) { + return issue.ChangeAssignee(doer, assigneeID) +} + +// ChangeAssignee changes the Assignee of this issue. +func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) { + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return err + } + + if err := issue.changeAssignee(sess, doer, assigneeID); err != nil { + return err + } + + return sess.Commit() +} + +func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64) (err error) { + + // Update the assignee + removed, err := updateIssueAssignee(sess, issue, assigneeID) + if err != nil { + return fmt.Errorf("UpdateIssueUserByAssignee: %v", err) + } + + // Repo infos + if err = issue.loadRepo(sess); err != nil { + return fmt.Errorf("loadRepo: %v", err) + } + + // Comment + if _, err = createAssigneeComment(sess, doer, issue.Repo, issue, assigneeID, removed); err != nil { + return fmt.Errorf("createAssigneeComment: %v", err) + } + + if issue.IsPull { + issue.PullRequest = &PullRequest{Issue: issue} + apiPullRequest := &api.PullRequestPayload{ + Index: issue.Index, + PullRequest: issue.PullRequest.APIFormat(), + Repository: issue.Repo.APIFormat(AccessModeNone), + Sender: doer.APIFormat(), + } + if removed { + apiPullRequest.Action = api.HookIssueUnassigned + } else { + apiPullRequest.Action = api.HookIssueAssigned + } + if err := PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest); err != nil { + log.Error(4, "PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err) + return nil + } + } + go HookQueue.Add(issue.RepoID) + return nil +} + +// UpdateAPIAssignee is a helper function to add or delete one or multiple issue assignee(s) +// Deleting is done the Github way (quote from their api documentation): +// https://developer.github.com/v3/issues/#edit-an-issue +// "assignees" (array): Logins for Users to assign to this issue. +// Pass one or more user logins to replace the set of assignees on this Issue. +// Send an empty array ([]) to clear all assignees from the Issue. +func UpdateAPIAssignee(issue *Issue, oneAssignee string, multipleAssignees []string, doer *User) (err error) { + var allNewAssignees []*User + + // Keep the old assignee thingy for compatibility reasons + if oneAssignee != "" { + // Prevent double adding assignees + var isDouble bool + for _, assignee := range multipleAssignees { + if assignee == oneAssignee { + isDouble = true + break + } + } + + if !isDouble { + multipleAssignees = append(multipleAssignees, oneAssignee) + } + } + + // Loop through all assignees to add them + for _, assigneeName := range multipleAssignees { + assignee, err := GetUserByName(assigneeName) + if err != nil { + return err + } + + allNewAssignees = append(allNewAssignees, assignee) + } + + // Delete all old assignees not passed + if err = DeleteNotPassedAssignee(issue, doer, allNewAssignees); err != nil { + return err + } + + // Add all new assignees + // Update the assignee. The function will check if the user exists, is already + // assigned (which he shouldn't as we deleted all assignees before) and + // has access to the repo. + for _, assignee := range allNewAssignees { + // Extra method to prevent double adding (which would result in removing) + err = AddAssigneeIfNotAssigned(issue, doer, assignee.ID) + if err != nil { + return err + } + } + + return +} + +// MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs +func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string) (assigneeIDs []int64, err error) { + + // Keeping the old assigning method for compatibility reasons + if oneAssignee != "" { + + // Prevent double adding assignees + var isDouble bool + for _, assignee := range multipleAssignees { + if assignee == oneAssignee { + isDouble = true + break + } + } + + if !isDouble { + multipleAssignees = append(multipleAssignees, oneAssignee) + } + } + + // Get the IDs of all assignees + assigneeIDs = GetUserIDsByNames(multipleAssignees) + + return +} diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go new file mode 100644 index 00000000000..32478121980 --- /dev/null +++ b/models/issue_assignees_test.go @@ -0,0 +1,71 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUpdateAssignee(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + + // Fake issue with assignees + issue, err := GetIssueByID(1) + assert.NoError(t, err) + + // Assign multiple users + user2, err := GetUserByID(2) + assert.NoError(t, err) + err = UpdateAssignee(issue, &User{ID: 1}, user2.ID) + assert.NoError(t, err) + + user3, err := GetUserByID(3) + assert.NoError(t, err) + err = UpdateAssignee(issue, &User{ID: 1}, user3.ID) + assert.NoError(t, err) + + user1, err := GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him + assert.NoError(t, err) + err = UpdateAssignee(issue, &User{ID: 1}, user1.ID) + assert.NoError(t, err) + + // Check if he got removed + isAssigned, err := IsUserAssignedToIssue(issue, user1) + assert.NoError(t, err) + assert.False(t, isAssigned) + + // Check if they're all there + assignees, err := GetAssigneesByIssue(issue) + assert.NoError(t, err) + + var expectedAssignees []*User + expectedAssignees = append(expectedAssignees, user2) + expectedAssignees = append(expectedAssignees, user3) + + for in, assignee := range assignees { + assert.Equal(t, assignee.ID, expectedAssignees[in].ID) + } + + // Check if the user is assigned + isAssigned, err = IsUserAssignedToIssue(issue, user2) + assert.NoError(t, err) + assert.True(t, isAssigned) + + // This user should not be assigned + isAssigned, err = IsUserAssignedToIssue(issue, &User{ID: 4}) + assert.NoError(t, err) + assert.False(t, isAssigned) + + // Clean everyone + err = DeleteNotPassedAssignee(issue, user1, []*User{}) + assert.NoError(t, err) + + // Check they're gone + assignees, err = GetAssigneesByIssue(issue) + assert.NoError(t, err) + assert.Equal(t, 0, len(assignees)) +} diff --git a/models/issue_comment.go b/models/issue_comment.go index 144a2dda222..a7008780bb9 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -88,23 +88,22 @@ const ( // Comment represents a comment in commit and issue page. type Comment struct { - ID int64 `xorm:"pk autoincr"` - Type CommentType - PosterID int64 `xorm:"INDEX"` - Poster *User `xorm:"-"` - IssueID int64 `xorm:"INDEX"` - LabelID int64 - Label *Label `xorm:"-"` - OldMilestoneID int64 - MilestoneID int64 - OldMilestone *Milestone `xorm:"-"` - Milestone *Milestone `xorm:"-"` - OldAssigneeID int64 - AssigneeID int64 - Assignee *User `xorm:"-"` - OldAssignee *User `xorm:"-"` - OldTitle string - NewTitle string + ID int64 `xorm:"pk autoincr"` + Type CommentType + PosterID int64 `xorm:"INDEX"` + Poster *User `xorm:"-"` + IssueID int64 `xorm:"INDEX"` + LabelID int64 + Label *Label `xorm:"-"` + OldMilestoneID int64 + MilestoneID int64 + OldMilestone *Milestone `xorm:"-"` + Milestone *Milestone `xorm:"-"` + AssigneeID int64 + RemovedAssignee bool + Assignee *User `xorm:"-"` + OldTitle string + NewTitle string CommitID int64 Line int64 // - previous line / + proposed line @@ -259,18 +258,9 @@ func (c *Comment) LoadMilestone() error { return nil } -// LoadAssignees if comment.Type is CommentTypeAssignees, then load assignees -func (c *Comment) LoadAssignees() error { +// LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees +func (c *Comment) LoadAssigneeUser() error { var err error - if c.OldAssigneeID > 0 { - c.OldAssignee, err = getUserByID(x, c.OldAssigneeID) - if err != nil { - if !IsErrUserNotExist(err) { - return err - } - c.OldAssignee = NewGhostUser() - } - } if c.AssigneeID > 0 { c.Assignee, err = getUserByID(x, c.AssigneeID) @@ -382,21 +372,21 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err LabelID = opts.Label.ID } comment := &Comment{ - Type: opts.Type, - PosterID: opts.Doer.ID, - Poster: opts.Doer, - IssueID: opts.Issue.ID, - LabelID: LabelID, - OldMilestoneID: opts.OldMilestoneID, - MilestoneID: opts.MilestoneID, - OldAssigneeID: opts.OldAssigneeID, - AssigneeID: opts.AssigneeID, - CommitID: opts.CommitID, - CommitSHA: opts.CommitSHA, - Line: opts.LineNum, - Content: opts.Content, - OldTitle: opts.OldTitle, - NewTitle: opts.NewTitle, + Type: opts.Type, + PosterID: opts.Doer.ID, + Poster: opts.Doer, + IssueID: opts.Issue.ID, + LabelID: LabelID, + OldMilestoneID: opts.OldMilestoneID, + MilestoneID: opts.MilestoneID, + RemovedAssignee: opts.RemovedAssignee, + AssigneeID: opts.AssigneeID, + CommitID: opts.CommitID, + CommitSHA: opts.CommitSHA, + Line: opts.LineNum, + Content: opts.Content, + OldTitle: opts.OldTitle, + NewTitle: opts.NewTitle, TreePath: opts.TreePath, ReviewID: opts.ReviewID, } @@ -540,14 +530,14 @@ func createMilestoneComment(e *xorm.Session, doer *User, repo *Repository, issue }) } -func createAssigneeComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, oldAssigneeID, assigneeID int64) (*Comment, error) { +func createAssigneeComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue, assigneeID int64, removedAssignee bool) (*Comment, error) { return createComment(e, &CreateCommentOptions{ - Type: CommentTypeAssignees, - Doer: doer, - Repo: repo, - Issue: issue, - OldAssigneeID: oldAssigneeID, - AssigneeID: assigneeID, + Type: CommentTypeAssignees, + Doer: doer, + Repo: repo, + Issue: issue, + RemovedAssignee: removedAssignee, + AssigneeID: assigneeID, }) } @@ -608,19 +598,19 @@ type CreateCommentOptions struct { Issue *Issue Label *Label - OldMilestoneID int64 - MilestoneID int64 - OldAssigneeID int64 - AssigneeID int64 - OldTitle string - NewTitle string - CommitID int64 - CommitSHA string - LineNum int64 + OldMilestoneID int64 + MilestoneID int64 + AssigneeID int64 + RemovedAssignee bool + OldTitle string + NewTitle string + CommitID int64 + CommitSHA string + LineNum int64 TreePath string ReviewID int64 - Content string - Attachments []string // UUIDs of attachments + Content string + Attachments []string // UUIDs of attachments } // CreateComment creates comment of issue or commit. diff --git a/models/issue_list.go b/models/issue_list.go index 01a1a15f443..05130a6eefc 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -154,38 +154,38 @@ func (issues IssueList) loadMilestones(e Engine) error { return nil } -func (issues IssueList) getAssigneeIDs() []int64 { - var ids = make(map[int64]struct{}, len(issues)) - for _, issue := range issues { - if _, ok := ids[issue.AssigneeID]; !ok { - ids[issue.AssigneeID] = struct{}{} - } - } - return keysInt64(ids) -} - func (issues IssueList) loadAssignees(e Engine) error { - assigneeIDs := issues.getAssigneeIDs() - if len(assigneeIDs) == 0 { + if len(issues) == 0 { return nil } - assigneeMaps := make(map[int64]*User, len(assigneeIDs)) - err := e. - In("id", assigneeIDs). - Find(&assigneeMaps) + type AssigneeIssue struct { + IssueAssignee *IssueAssignees `xorm:"extends"` + Assignee *User `xorm:"extends"` + } + + var assignees = make(map[int64][]*User, len(issues)) + rows, err := e.Table("issue_assignees"). + Join("INNER", "user", "`user`.id = `issue_assignees`.assignee_id"). + In("`issue_assignees`.issue_id", issues.getIssueIDs()). + Rows(new(AssigneeIssue)) if err != nil { return err } + defer rows.Close() - for _, issue := range issues { - if issue.AssigneeID <= 0 { - continue - } - var ok bool - if issue.Assignee, ok = assigneeMaps[issue.AssigneeID]; !ok { - issue.Assignee = NewGhostUser() + for rows.Next() { + var assigneeIssue AssigneeIssue + err = rows.Scan(&assigneeIssue) + if err != nil { + return err } + + assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee) + } + + for _, issue := range issues { + issue.Assignees = assignees[issue.ID] } return nil } diff --git a/models/issue_mail.go b/models/issue_mail.go index 08e4eed584d..179bb6527b5 100644 --- a/models/issue_mail.go +++ b/models/issue_mail.go @@ -46,9 +46,16 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content participants = append(participants, issue.Poster) } - // Assignee must receive any communications - if issue.Assignee != nil && issue.AssigneeID > 0 && issue.AssigneeID != doer.ID { - participants = append(participants, issue.Assignee) + // Assignees must receive any communications + assignees, err := GetAssigneesByIssue(issue) + if err != nil { + return err + } + + for _, assignee := range assignees { + if assignee.ID != doer.ID { + participants = append(participants, assignee) + } } tos := make([]string, 0, len(watchers)) // List of email addresses. diff --git a/models/issue_milestone.go b/models/issue_milestone.go index 949932fb2bf..8de1f975713 100644 --- a/models/issue_milestone.go +++ b/models/issue_milestone.go @@ -24,7 +24,7 @@ type Milestone struct { NumClosedIssues int NumOpenIssues int `xorm:"-"` Completeness int // Percentage(1-100). - IsOverDue bool `xorm:"-"` + IsOverdue bool `xorm:"-"` DeadlineString string `xorm:"-"` DeadlineUnix util.TimeStamp @@ -52,7 +52,7 @@ func (m *Milestone) AfterLoad() { m.DeadlineString = m.DeadlineUnix.Format("2006-01-02") if util.TimeStampNow() >= m.DeadlineUnix { - m.IsOverDue = true + m.IsOverdue = true } } diff --git a/models/issue_user.go b/models/issue_user.go index 1aded0b4404..de5a185aece 100644 --- a/models/issue_user.go +++ b/models/issue_user.go @@ -6,6 +6,8 @@ package models import ( "fmt" + + "github.com/go-xorm/xorm" ) // IssueUser represents an issue-user relation. @@ -14,7 +16,6 @@ type IssueUser struct { UID int64 `xorm:"INDEX"` // User ID. IssueID int64 IsRead bool - IsAssigned bool IsMentioned bool } @@ -32,9 +33,8 @@ func newIssueUsers(e Engine, repo *Repository, issue *Issue) error { issueUsers := make([]*IssueUser, 0, len(assignees)+1) for _, assignee := range assignees { issueUsers = append(issueUsers, &IssueUser{ - IssueID: issue.ID, - UID: assignee.ID, - IsAssigned: assignee.ID == issue.AssigneeID, + IssueID: issue.ID, + UID: assignee.ID, }) isPosterAssignee = isPosterAssignee || assignee.ID == issue.PosterID } @@ -51,34 +51,38 @@ func newIssueUsers(e Engine, repo *Repository, issue *Issue) error { return nil } -func updateIssueUserByAssignee(e Engine, issue *Issue) (err error) { - if _, err = e.Exec("UPDATE `issue_user` SET is_assigned = ? WHERE issue_id = ?", false, issue.ID); err != nil { - return err +func updateIssueAssignee(e *xorm.Session, issue *Issue, assigneeID int64) (removed bool, err error) { + + // Check if the user exists + _, err = GetUserByID(assigneeID) + if err != nil { + return false, err } - // Assignee ID equals to 0 means clear assignee. - if issue.AssigneeID > 0 { - if _, err = e.Exec("UPDATE `issue_user` SET is_assigned = ? WHERE uid = ? AND issue_id = ?", true, issue.AssigneeID, issue.ID); err != nil { - return err + // Check if the submitted user is already assigne, if yes delete him otherwise add him + var toBeDeleted bool + for _, assignee := range issue.Assignees { + if assignee.ID == assigneeID { + toBeDeleted = true + break } } - return updateIssue(e, issue) -} + assigneeIn := IssueAssignees{AssigneeID: assigneeID, IssueID: issue.ID} -// UpdateIssueUserByAssignee updates issue-user relation for assignee. -func UpdateIssueUserByAssignee(issue *Issue) (err error) { - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return err - } - - if err = updateIssueUserByAssignee(sess, issue); err != nil { - return err + if toBeDeleted { + _, err = e.Delete(assigneeIn) + if err != nil { + return toBeDeleted, err + } + } else { + _, err = e.Insert(assigneeIn) + if err != nil { + return toBeDeleted, err + } } - return sess.Commit() + return toBeDeleted, nil } // UpdateIssueUserByRead updates issue-user relation for reading. diff --git a/models/issue_user_test.go b/models/issue_user_test.go index e3ebfa8fa28..a333bc86199 100644 --- a/models/issue_user_test.go +++ b/models/issue_user_test.go @@ -32,23 +32,6 @@ func Test_newIssueUsers(t *testing.T) { AssertExistsAndLoadBean(t, &IssueUser{IssueID: newIssue.ID, UID: repo.OwnerID}) } -func TestUpdateIssueUserByAssignee(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) - - // artificially change assignee in issue_user table - AssertSuccessfulInsert(t, &IssueUser{IssueID: issue.ID, UID: 5, IsAssigned: true}) - _, err := x.Cols("is_assigned"). - Update(&IssueUser{IsAssigned: false}, &IssueUser{IssueID: issue.ID, UID: issue.AssigneeID}) - assert.NoError(t, err) - - assert.NoError(t, UpdateIssueUserByAssignee(issue)) - - // issue_user table should now be correct again - AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: issue.AssigneeID}, "is_assigned=1") - AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: 5}, "is_assigned=0") -} - func TestUpdateIssueUserByRead(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index fef6374bc08..06ae9faf420 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -181,6 +181,8 @@ var migrations = []Migration{ // v63 -> v64 NewMigration("add language column for user setting", addLanguageSetting), // v64 -> v65 + NewMigration("add multiple assignees", addMultipleAssignees), + // v65 -> v66 NewMigration("add review", addReview), } @@ -231,7 +233,7 @@ Please try to upgrade to a lower version (>= v0.6.0) first, then upgrade to curr return nil } -func dropTableColumns(x *xorm.Engine, tableName string, columnNames ...string) (err error) { +func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...string) (err error) { if tableName == "" || len(columnNames) == 0 { return nil } @@ -247,17 +249,10 @@ func dropTableColumns(x *xorm.Engine, tableName string, columnNames ...string) ( } cols += "DROP COLUMN `" + col + "`" } - if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { + if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `%s` %s", tableName, cols)); err != nil { return fmt.Errorf("Drop table `%s` columns %v: %v", tableName, columnNames, err) } case setting.UseMSSQL: - sess := x.NewSession() - defer sess.Close() - - if err = sess.Begin(); err != nil { - return err - } - cols := "" for _, col := range columnNames { if cols != "" { diff --git a/models/migrations/v56.go b/models/migrations/v56.go index 1f96cc543e6..79f8ce0ba5c 100644 --- a/models/migrations/v56.go +++ b/models/migrations/v56.go @@ -9,5 +9,15 @@ import ( ) func removeIsOwnerColumnFromOrgUser(x *xorm.Engine) (err error) { - return dropTableColumns(x, "org_user", "is_owner", "num_teams") + sess := x.NewSession() + defer sess.Close() + + if err = sess.Begin(); err != nil { + return err + } + + if err := dropTableColumns(sess, "org_user", "is_owner", "num_teams"); err != nil { + return err + } + return sess.Commit() } diff --git a/models/migrations/v64.go b/models/migrations/v64.go index 4924b41cebe..67ce3a9196a 100644 --- a/models/migrations/v64.go +++ b/models/migrations/v64.go @@ -5,27 +5,127 @@ package migrations import ( - "fmt" - "code.gitea.io/gitea/modules/util" "github.com/go-xorm/xorm" ) -func addReview(x *xorm.Engine) error { - // Review see models/review.go - type Review struct { - ID int64 `xorm:"pk autoincr"` - Type string - ReviewerID int64 `xorm:"index"` - IssueID int64 `xorm:"index"` - Content string +func addMultipleAssignees(x *xorm.Engine) error { + + // Redeclare issue struct + type Issue struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"` + Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository. + PosterID int64 `xorm:"INDEX"` + Title string `xorm:"name"` + Content string `xorm:"TEXT"` + MilestoneID int64 `xorm:"INDEX"` + Priority int + AssigneeID int64 `xorm:"INDEX"` + IsClosed bool `xorm:"INDEX"` + IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not. + NumComments int + Ref string + + DeadlineUnix util.TimeStamp `xorm:"INDEX"` + CreatedUnix util.TimeStamp `xorm:"INDEX created"` + UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` + ClosedUnix util.TimeStamp `xorm:"INDEX"` + } + + // Updated the comment table + type Comment struct { + ID int64 `xorm:"pk autoincr"` + Type int + PosterID int64 `xorm:"INDEX"` + IssueID int64 `xorm:"INDEX"` + LabelID int64 + OldMilestoneID int64 + MilestoneID int64 + OldAssigneeID int64 + AssigneeID int64 + RemovedAssignee bool + OldTitle string + NewTitle string + + CommitID int64 + Line int64 + Content string `xorm:"TEXT"` + RenderedContent string `xorm:"-"` + CreatedUnix util.TimeStamp `xorm:"INDEX created"` UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` + + // Reference issue in commit message + CommitSHA string `xorm:"VARCHAR(40)"` + } + + // Create the table + type IssueAssignees struct { + ID int64 `xorm:"pk autoincr"` + AssigneeID int64 `xorm:"INDEX"` + IssueID int64 `xorm:"INDEX"` + } + + if err := x.Sync2(IssueAssignees{}); err != nil { + return err + } + + if err := x.Sync2(Comment{}); err != nil { + return err + } + + // Range over all issues and insert a new entry for each issue/assignee + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return err + } + + allIssues := []Issue{} + if err := sess.Find(&allIssues); err != nil { + return err + } + + for _, issue := range allIssues { + if issue.AssigneeID != 0 { + _, err := sess.Insert(IssueAssignees{IssueID: issue.ID, AssigneeID: issue.AssigneeID}) + if err != nil { + sess.Rollback() + return err + } + } + } + + // Migrate comments + // First update everything to not have nulls in db + if _, err := sess.Where("type = ?", 9).Cols("removed_assignee").Update(Comment{RemovedAssignee: false}); err != nil { + return err + } + + allAssignementComments := []Comment{} + if err := sess.Where("type = ?", 9).Find(&allAssignementComments); err != nil { + return err + } + + for _, comment := range allAssignementComments { + // Everytime where OldAssigneeID is > 0, the assignement was removed. + if comment.OldAssigneeID > 0 { + _, err := sess.ID(comment.ID).Update(Comment{RemovedAssignee: true}) + if err != nil { + return err + } + } + } + + if err := dropTableColumns(sess, "issue", "assignee_id"); err != nil { + return err } - if err := x.Sync2(new(Review)); err != nil { - return fmt.Errorf("Sync2: %v", err) + if err := dropTableColumns(sess, "issue_user", "is_assigned"); err != nil { + return err } - return nil + return sess.Commit() } diff --git a/models/models.go b/models/models.go index b9fcb56efb3..63bea3c8c43 100644 --- a/models/models.go +++ b/models/models.go @@ -119,6 +119,7 @@ func init() { new(RepoIndexerStatus), new(LFSLock), new(Reaction), + new(IssueAssignees), new(Review), ) diff --git a/models/pull.go b/models/pull.go index 23b3888aec5..fb5fcf46fbd 100644 --- a/models/pull.go +++ b/models/pull.go @@ -198,6 +198,7 @@ func (pr *PullRequest) APIFormat() *api.PullRequest { Labels: apiIssue.Labels, Milestone: apiIssue.Milestone, Assignee: apiIssue.Assignee, + Assignees: apiIssue.Assignees, State: apiIssue.State, Comments: apiIssue.Comments, HTMLURL: pr.Issue.HTMLURL(), @@ -719,7 +720,7 @@ func (pr *PullRequest) testPatch() (err error) { } // NewPullRequest creates new pull request with labels for repository. -func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte) (err error) { +func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []string, pr *PullRequest, patch []byte, assigneeIDs []int64) (err error) { sess := x.NewSession() defer sess.Close() if err = sess.Begin(); err != nil { @@ -732,7 +733,11 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str LabelIDs: labelIDs, Attachments: uuids, IsPull: true, + AssigneeIDs: assigneeIDs, }); err != nil { + if IsErrUserDoesNotHaveAccessToRepo(err) { + return err + } return fmt.Errorf("newIssue: %v", err) } diff --git a/models/repo.go b/models/repo.go index 43fb1e0c733..4a7eb859c4d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -600,9 +600,9 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) { return repo.getAssignees(x) } -// GetAssigneeByID returns the user that has write access of repository by given ID. -func (repo *Repository) GetAssigneeByID(userID int64) (*User, error) { - return GetAssigneeByID(repo, userID) +// GetUserIfHasWriteAccess returns the user that has write access of repository by given ID. +func (repo *Repository) GetUserIfHasWriteAccess(userID int64) (*User, error) { + return GetUserIfHasWriteAccess(repo, userID) } // GetMilestoneByID returns the milestone belongs to repository by given ID. diff --git a/models/user.go b/models/user.go index 106d79ffcc2..8f5ee6e5a7e 100644 --- a/models/user.go +++ b/models/user.go @@ -993,7 +993,7 @@ func deleteUser(e *xorm.Session, u *User) error { // ***** END: PublicKey ***** // Clear assignee. - if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.ID); err != nil { + if err = clearAssigneeByUserID(e, u.ID); err != nil { return fmt.Errorf("clear assignee: %v", err) } @@ -1110,8 +1110,8 @@ func GetUserByID(id int64) (*User, error) { return getUserByID(x, id) } -// GetAssigneeByID returns the user with write access of repository by given ID. -func GetAssigneeByID(repo *Repository, userID int64) (*User, error) { +// GetUserIfHasWriteAccess returns the user with write access of repository by given ID. +func GetUserIfHasWriteAccess(repo *Repository, userID int64) (*User, error) { has, err := HasAccess(userID, repo, AccessModeWrite) if err != nil { return nil, err diff --git a/models/webhook_dingtalk.go b/models/webhook_dingtalk.go index e25e989084f..719ffcae736 100644 --- a/models/webhook_dingtalk.go +++ b/models/webhook_dingtalk.go @@ -118,8 +118,12 @@ func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload, title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) text = p.PullRequest.Body case api.HookIssueAssigned: + list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID}) + if err != nil { + return &DingtalkPayload{}, err + } title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, - p.PullRequest.Assignee.UserName, p.Index, p.PullRequest.Title) + list, p.Index, p.PullRequest.Title) text = p.PullRequest.Body case api.HookIssueUnassigned: title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) diff --git a/models/webhook_discord.go b/models/webhook_discord.go index 6d39d8b9939..40d9d58992f 100644 --- a/models/webhook_discord.go +++ b/models/webhook_discord.go @@ -191,8 +191,12 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) text = p.PullRequest.Body color = warnColor case api.HookIssueAssigned: + list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID}) + if err != nil { + return &DiscordPayload{}, err + } title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, - p.PullRequest.Assignee.UserName, p.Index, p.PullRequest.Title) + list, p.Index, p.PullRequest.Title) text = p.PullRequest.Body color = successColor case api.HookIssueUnassigned: diff --git a/models/webhook_slack.go b/models/webhook_slack.go index dd25a8d7df7..256819adc56 100644 --- a/models/webhook_slack.go +++ b/models/webhook_slack.go @@ -172,8 +172,12 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S text = fmt.Sprintf("[%s] Pull request edited: %s by %s", p.Repository.FullName, titleLink, senderLink) attachmentText = SlackTextFormatter(p.PullRequest.Body) case api.HookIssueAssigned: + list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID}) + if err != nil { + return &SlackPayload{}, err + } text = fmt.Sprintf("[%s] Pull request assigned to %s: %s by %s", p.Repository.FullName, - SlackLinkFormatter(setting.AppURL+p.PullRequest.Assignee.UserName, p.PullRequest.Assignee.UserName), + SlackLinkFormatter(setting.AppURL+list, list), titleLink, senderLink) case api.HookIssueUnassigned: text = fmt.Sprintf("[%s] Pull request unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink) diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 4d433484d80..8b57e7eda9a 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -254,6 +254,7 @@ func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors type CreateIssueForm struct { Title string `binding:"Required;MaxSize(255)"` LabelIDs string `form:"label_ids"` + AssigneeIDs string `form:"assignee_ids"` Ref string `form:"ref"` MilestoneID int64 AssigneeID int64 diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index 956ebd944be..5906abcd1d2 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -44,6 +44,7 @@ type InstallForm struct { EnableOpenIDSignIn bool EnableOpenIDSignUp bool DisableRegistration bool + AllowOnlyExternalRegistration bool EnableCaptcha bool RequireSignInView bool DefaultKeepEmailPrivate bool diff --git a/modules/context/repo.go b/modules/context/repo.go index f3ae33cb503..1fe5482ce1a 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -99,8 +99,9 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b // Checking for following: // 1. Is timetracker enabled // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? + isAssigned, _ := models.IsUserAssignedToIssue(issue, user) return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || - r.IsWriter() || issue.IsPoster(user.ID) || issue.AssigneeID == user.ID) + r.IsWriter() || issue.IsPoster(user.ID) || isAssigned) } // GetCommitsCount returns cached commit count for current view diff --git a/modules/setting/setting.go b/modules/setting/setting.go index af1a2824292..9f20d955cce 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1143,6 +1143,7 @@ var Service struct { ResetPwdCodeLives int RegisterEmailConfirm bool DisableRegistration bool + AllowOnlyExternalRegistration bool ShowRegistrationButton bool RequireSignInView bool EnableNotifyMail bool @@ -1168,7 +1169,8 @@ func newService() { Service.ActiveCodeLives = sec.Key("ACTIVE_CODE_LIVE_MINUTES").MustInt(180) Service.ResetPwdCodeLives = sec.Key("RESET_PASSWD_CODE_LIVE_MINUTES").MustInt(180) Service.DisableRegistration = sec.Key("DISABLE_REGISTRATION").MustBool() - Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!Service.DisableRegistration) + Service.AllowOnlyExternalRegistration = sec.Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").MustBool() + Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index 05b33b4174f..81d373b9521 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -271,9 +271,6 @@ issues.new.no_milestone=Няма етап issues.new.clear_milestone=Изчисти етап issues.new.open_milestone=Отворени етапи issues.new.closed_milestone=Затворени етапи -issues.new.assignee=Изпълнител -issues.new.clear_assignee=Изчисти изпълнител -issues.new.no_assignee=Няма изпълнител issues.create=Създай задача issues.new_label=Нов етикет issues.create_label=Създай етикет diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 8008b64f976..36204ba736c 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -270,9 +270,6 @@ issues.new.no_milestone=Bez milníku issues.new.clear_milestone=Smazat milník issues.new.open_milestone=Otevřít milník issues.new.closed_milestone=Zavřené milníky -issues.new.assignee=Zpracovatel -issues.new.clear_assignee=Smazat zpracovatele -issues.new.no_assignee=Bez zpracovatele issues.create=Vytvořit úkol issues.new_label=Nový štítek issues.create_label=Vytvořit štítek diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index d6312487827..ec7a8634db6 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -81,7 +81,7 @@ err_empty_admin_password=Das Administrator-Passwort darf nicht leer sein. general_title=Allgemeine Einstellungen app_name=Seitentitel -app_name_helper=Gebe hier den Namen deines Unternehmens ein. +app_name_helper=Du kannst hier den Namen deines Unternehmens eingeben. repo_path=Repository-Verzeichnis repo_path_helper=Remote-Git-Repositories werden in diesem Verzeichnis gespeichert. lfs_path=Git LFS-Wurzelpfad @@ -136,6 +136,7 @@ test_git_failed=Fehler beim Test des 'git' Kommandos: %v sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die 'gobuild'-Version). invalid_db_setting=Datenbankeinstellungen sind ungültig: %v invalid_repo_path=Repository-Verzeichnis ist ungültig: %v +run_user_not_match=Der "Ausführen als" Benutzer ist nicht der aktuelle Benutzer: %s -> %s save_config_failed=Fehler beim Speichern der Konfiguration: %v invalid_admin_setting=Administrator-Konto Einstellungen sind ungültig: %v install_success=Willkommen! Danke, dass du Gitea gewählt hast. Viel Spaß! @@ -157,7 +158,7 @@ show_more_repos=Zeige mehr Repositories… collaborative_repos=Gemeinschaftliche Repositories my_orgs=Meine Organisationen my_mirrors=Meine Mirrors -view_home=%s betrachten +view_home=%s ansehen search_repos=Finde ein Repository… issues.in_your_repos=Eigene Repositories @@ -188,6 +189,7 @@ confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an %s reset_password_mail_sent_prompt=Eine E-Mail wurde an %s gesendet. Bitte überprüfe dein Postfach innerhalb der nächsten %s, um das Passwort zurückzusetzen. active_your_account=Aktiviere dein Konto prohibit_login=Anmelden verboten +prohibit_login_desc=Dein Account wurde gesperrt, bitte wende dich an den Administrator. resent_limit_prompt=Du hast bereits eine Aktivierungs-E-Mail angefordert. Bitte warte 3 Minuten und probiere es dann nochmal. has_unconfirmed_mail=Hallo %s, du hast eine unbestätigte E-Mail-Adresse (%s). Wenn du keine Bestätigungs-E-Mail erhalten hast oder eine neue senden möchtest, klicke bitte auf den folgenden Button. resend_mail=Aktivierungs-E-Mail erneut verschicken @@ -208,7 +210,9 @@ login_userpass=Anmelden login_openid=OpenID openid_connect_submit=Verbinden openid_connect_title=Mit bestehendem Konto verbinden +openid_connect_desc=Die gewählte OpenID URI ist unbekannt. Ordne sie hier einem neuen Account zu. openid_register_title=Neues Konto einrichten +openid_register_desc=Die gewählte OpenID URI ist unbekannt. Ordne sie hier einem neuen Account zu. openid_signin_desc=Gib deine OpenID-URI ein. Zum Beispiel: https://anne.me, bob.openid.org.cn oder gnusocial.net/carry. disable_forgot_password_mail=Das Zurücksetzen von Passwörtern wurde deaktiviert. Bitte wende dich an den Administrator. @@ -279,6 +283,7 @@ unable_verify_ssh_key=Dein SSH-Key kann nicht überprüft werden, probiere es er auth_failed=Authentifizierung fehlgeschlagen: %v still_own_repo=Dein Konto besitzt ein oder mehrere Repositories. Diese müssen zuerst gelöscht oder übertragen werden. +still_has_org=Dein Account ist Mitglied in mindestens einer Organisation. Bitte verlasse diese zuerst. org_still_own_repo=Diese Organisation besitzt noch mindestens ein Repository. Bitte lösche oder übertrage diese zuerst. target_branch_not_exist=Die Ziel-Branch existiert nicht. @@ -370,11 +375,16 @@ openid_desc=Mit OpenID kannst du dich über einen Drittanbieter authentifizieren manage_ssh_keys=SSH-Schlüssel verwalten manage_gpg_keys=GPG-Schlüssel verwalten add_key=Schlüssel hinzufügen +ssh_desc=Diese öffentlichen SSH-Keys sind mit deinem Account verbunden. Der dazugehörigen privaten SSH-Keys geben dir vollen Zugriff auf deine Repositories. +gpg_desc=Diese öffentlichen GPG-Keys sind mit deinem Account verbunden. Halte die dazugehörigen privaten SSH-Keys geheim, da diese deine Commits signieren. ssh_helper=Brauchst du Hilfe? Hier ist Githubs Anleitung zum Erzeugen von SSH-Schlüsseln oder Lösen einfacher SSH-Probleme. gpg_helper=Brauchst du Hilfe? Hier ist GitHubs Anleitung über GPG. add_new_key=SSH-Schlüssel hinzufügen add_new_gpg_key=GPG-Schlüssel hinzufügen +ssh_key_been_used=Dieser SSH-Key wurde bereits zu deinem Account hinzugefügt. +ssh_key_name_used=Ein gleichnamiger SSH-Key existiert bereits in deinem Account. gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits. +gpg_no_key_email_found=Dieser GPG Schlüssel kann mit keiner E-Mail-Adresse deines Accounts verwendet werden. subkeys=Unterschlüssel key_id=Schlüssel-ID key_name=Schlüsselname @@ -402,6 +412,7 @@ hide_openid=Nicht im Profil anzeigen ssh_disabled=SSH ist deaktiviert manage_social=Verknüpfte soziale Konten verwalten +social_desc=Diese Accounts sind mit deinem Gitea-Konto verbunden. Schau dir alle Accounts an, um sicherzustellen dass du alle legitimiert hast, da man sich darüber in deinem Gitea-Konto anmelden kann. unbind=Trennen unbind_success=Das Konto wurde von deinem Gitea-Konto getrennt. @@ -414,7 +425,10 @@ generate_token=Token generieren generate_token_success=Ein neuer Token wurde generiert. Kopiere diesen, da er nicht erneut angezeigt wird. delete_token=Löschen access_token_deletion=Zugriffstoken löschen +access_token_deletion_desc=Wenn du ein Token löschst, haben die Anwendungen, die es nutzen keinen Zugriff mehr auf deinen Account. Fortfahren? +delete_token_success=Der Zugriffstoken wurde gelöscht. Anwendungen die diesen Token genutzt haben, haben nun keinen Zugriff mehr auf deinen Account. +twofa_desc=Zwei-Faktor-Authentifizierung trägt zu einer höheren Accountsicherheit bei. twofa_is_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung eingeschaltet. twofa_not_enrolled=Für dein Konto ist die Zwei-Faktor-Authentifizierung momentan nicht eingeschaltet. twofa_disable=Zwei-Faktor-Authentifizierung deaktivieren @@ -423,6 +437,7 @@ twofa_scratch_token_regenerated=Dein Einmalpasswort ist %s. Bewahre es an einem twofa_enroll=Zwei-Faktor-Authentifizierung aktivieren twofa_disable_note=Du kannst die Zwei-Faktor-Authentifizierung auch wieder deaktivieren. twofa_disable_desc=Wenn du die Zwei-Faktor-Authentifizierung deaktivierst, wird die Sicherheit deines Kontos verringert. Fortfahren? +regenerate_scratch_token_desc=Wenn du dein Einmalpasswort verlegt oder es bereits benutzt hast, kannst du es hier zurücksetzen. twofa_disabled=Zwei-Faktor-Authentifizierung wurde deaktiviert. scan_this_image=Scanne diese Grafik mit deiner Authentifizierungs-App: or_enter_secret=Oder gib das Secret ein: %s @@ -430,21 +445,34 @@ then_enter_passcode=Und gebe dann die angezeigte PIN der Anwendung ein: passcode_invalid=Die PIN ist falsch. Probiere es erneut. twofa_enrolled=Die Zwei-Faktor-Authentifizierung wurde für dein Konto aktiviert. Bewahre dein Einmalpasswort (%s) an einem sicheren Ort auf, da es nicht wieder angezeigt werden wird. +manage_account_links=Verknüpfte Accounts verwalten +manage_account_links_desc=Diese externen Accounts sind mit deinem Gitea-Account verknüpft. +account_links_not_available=Es sind keine externen Accounts mit diesem Gitea-Account verknüpft. +remove_account_link=Verknüpften Account entfernen +remove_account_link_desc=Wenn du den verknüpften Account entfernst, wirst du darüber nicht mehr auf deinen Gitea-Account zugreifen können. Fortfahren? +remove_account_link_success=Der verknüpfte Account wurde entfernt. orgs_none=Du bist kein Mitglied in einer Organisation. repos_none=Du besitzt keine Repositories delete_account=Konto löschen +delete_prompt=Wenn du fortfährst wird dein Account permanent gelöscht. Dies KANN NICHT rückgängig gemacht werden. confirm_delete_account=Löschen bestätigen delete_account_title=Benutzerkonto löschen +delete_account_desc=Bist du sicher, dass du diesen Account dauerhaft löschen möchtest? [repo] owner=Besitzer repo_name=Repository-Name repo_name_helper=Ein guter Repository-Name besteht normalerweise aus kurzen, unvergesslichen und einzigartigen Schlagwörtern. visibility=Sichtbarkeit +visiblity_helper=privates Repository +visiblity_helper_forced=Auf dieser Gitea-Instanz können nur private Repositories angelegt werden. +visiblity_fork_helper=(Eine Änderung dieses Wertes wirkt sich auf alle Forks aus) +clone_helper=Brauchst du Hilfe beim Klonen? Öffne die Hilfe. fork_repo=Repository forken fork_from=Fork von +fork_visiblity_helper=Die Sichtbarkeit einer geforkten Repository kann nicht geändert werden. repo_desc=Beschreibung repo_lang=Sprache repo_gitignore_helper=Wähle eine .gitignore-Vorlage aus. @@ -452,11 +480,16 @@ license=Lizenz license_helper=Wähle eine Lizenz aus. readme=README readme_helper=Wähle eine README-Vorlage aus. +auto_init=Repository initialisieren (Fügt .gitignore, License und README-Dateien hinzu) create_repo=Repository erstellen default_branch=Standardbranch mirror_prune=Entfernen +mirror_prune_desc=Entferne veraltete remote-tracking Referenzen mirror_interval=Spiegelintervall (gültige Zeiteinheiten sind 'h', 'm', 's') mirror_interval_invalid=Das Spiegel-Intervall ist ungültig. +mirror_address=Klonen via URL +mirror_address_desc=Bitte gebe alle benötigten Zugangsdaten in der URL an. +mirror_last_synced=Zuletzt synchronisiert watchers=Beobachter stargazers=Favorisiert von forks=Forks @@ -465,16 +498,22 @@ reactions_more=und %d weitere form.reach_limit_of_creation=Du hast bereits dein Limit von %d Repositories erreicht. form.name_reserved=Der Repository-Name '%s' ist reserviert. +form.name_pattern_not_allowed='%s' ist nicht erlaubt für Repository-Namen. migrate_type=Migrationstyp migrate_type_helper=Dieses Repository wird ein Mirror sein migrate_repo=Repository migrieren +migrate.clone_address=Migrations- / Klon-URL +migrate.clone_address_desc=Die HTTP(s) oder Klon-URL eines bereits existierenden Repositories migrate.clone_local_path=oder ein lokaler Serverpfad migrate.permission_denied=Du hast keine Berechtigung zum Importieren lokaler Repositories. +migrate.invalid_local_path=Der lokale Pfad ist ungültig, existiert nicht oder ist kein Ordner. migrate.failed=Fehler bei der Migration: %v +migrate.lfs_mirror_unsupported=Spiegeln von LFS-Objekten wird nicht unterstützt - nutze stattdessen 'git lfs fetch --all' und 'git lfs push --all'. mirror_from=Mirror von forked_from=geforkt von +fork_from_self=Du kannst kein Repository forken, das dir bereits gehört. copy_link=Kopieren copy_link_success=Der Link wurde kopiert copy_link_error=Verwende ⌘-C oder Strg-C zum Kopieren @@ -513,11 +552,13 @@ file_permalink=Permalink file_too_large=Die Datei ist zu groß zum Anzeigen. video_not_supported_in_browser=Dein Browser unterstützt das HTML5 'video'-Tag nicht. stored_lfs=Gespeichert mit Git LFS +commit_graph=Commit graph editor.new_file=Neue Datei editor.upload_file=Datei hochladen editor.edit_file=Datei bearbeiten editor.preview_changes=Vorschau der Änderungen +editor.cannot_edit_non_text_files=Binärdateien können nicht im Webinterface bearbeitet werden. editor.edit_this_file=Datei bearbeiten editor.fork_before_edit=Du musst dieses Repository forken, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen. editor.delete_this_file=Datei löschen @@ -542,6 +583,7 @@ editor.directory_is_a_file=Der Verzeichnisname '%s' wird bereits als Dateiname i editor.file_is_a_symlink='%s' ist ein symolischer Link. Symbolische Links können mit dem Web Editor nicht bearbeitet werden. editor.filename_is_a_directory=Der Dateiname '%s' wird bereits als Verzeichnisname in diesem Repository verwendet. editor.file_editing_no_longer_exists=Die bearbeitete Datei '%s' existiert nicht mehr in diesem Repository. +editor.file_changed_while_editing=Der Inhalt der Datei hat sich seit dem Beginn der Bearbeitung geändert. Hier klicken um die Änderungen anzusehen, oder Änderungen erneut comitten um sie zu überschreiben. editor.file_already_exists=Eine Datei mit dem Namen '%s' ist bereits in diesem Repository vorhanden. editor.no_changes_to_show=Keine Änderungen vorhanden. editor.fail_to_update_file=Fehler beim Ändern/Erstellen der Datei '%s'. Fehler: %v @@ -564,8 +606,9 @@ commits.signed_by=Signiert von commits.gpg_key_id=GPG Schlüssel-ID ext_issues=Externe Issues +ext_issues.desc=Link zu externem Issuetracker. -issues.desc=Bearbeite Bug Reports, Aufgaben und Meilensteine. +issues.desc=Verwalte Bug-Reports, Aufgaben und Meilensteine. issues.new=Neuer Issue issues.new.labels=Label issues.new.no_label=Kein Label @@ -575,9 +618,9 @@ issues.new.no_milestone=Kein Meilenstein issues.new.clear_milestone=Meilenstein entfernen issues.new.open_milestone=Offene Meilensteine issues.new.closed_milestone=Geschlossene Meilensteine -issues.new.assignee=Zuständig -issues.new.clear_assignee=Zuständigkeit entfernen -issues.new.no_assignee=Niemand zuständig +issues.new.assignees=Zuständig +issues.new.clear_assignees=Zuständige entfernen +issues.new.no_assignees=Niemand zugewiesen issues.no_ref=Keine Branch/Tag angegeben issues.create=Issue erstellen issues.new_label=Neues Label @@ -686,12 +729,19 @@ issues.add_time_hours=Stunden issues.add_time_minutes=Minuten issues.cancel_tracking=Abbrechen issues.cancel_tracking_history=hat die Zeiterfassung %s abgebrochen +issues.time_spent_from_all_authors=`Aufgewendete Zeit: %s` +issues.due_date_form_add=Fälligkeitsdatum hinzufügen +issues.due_date_form_update=Fälligkeitsdatum ändern +issues.due_date_form_remove=Fälligkeitsdatum löschen +issues.due_date_not_set=Kein Fälligkeitsdatum gesetzt. +issues.due_date_overdue=Überfällig pulls.new=Neuer Pull-Request pulls.compare_changes=Neuer Pull-Request pulls.compare_compare=pull von pulls.filter_branch=Branch filtern pulls.no_results=Keine Ergebnisse verfügbar. +pulls.nothing_to_compare=Diese Branches sind identisch. Es muss kein Pull-Request erstellt werden. pulls.create=Pull-Request erstellen pulls.title_desc=möchte %[1]d Commits von %[2]s nach %[3]s zusammenführen pulls.merged_title_desc=hat %[1]d Commits von %[2]s nach %[3]s %[4]s zusammengeführt @@ -838,10 +888,16 @@ settings.convert_confirm=Repository umwandeln settings.convert_succeed=Das Mirror-Repository wurde erfolgreich in ein normales Repository umgewandelt. settings.transfer=Besitz übertragen settings.transfer_desc=Übertrage dieses Repository auf einen anderen Benutzer oder eine Organisation in der Du Admin-Rechte hast. +settings.transfer_notices_1=- Du wirst keinen Zugriff mehr haben, wenn der neue Besitzer ein individueller Benutzer ist. +settings.transfer_notices_2=- Du wirst weiterhin Zugriff haben, wenn der neue Besitzer eine Organisation ist und du einer der Besitzer bist. +settings.transfer_form_title=Gib den Repository-Namen zur Bestätigung ein: settings.wiki_delete=Wiki-Daten löschen +settings.wiki_delete_desc=Das Löschen von Wiki-Daten kann nicht rückgängig gemacht werden. Bitte sei vorsichtig. +settings.wiki_delete_notices_1=- Dies löscht und deaktiviert das Wiki für %s. settings.confirm_wiki_delete=Wiki-Daten löschen settings.wiki_deletion_success=Repository Wiki-Daten wurden gelöscht. settings.delete=Dieses Repository löschen +settings.delete_desc=Wenn dieses Repository gelöscht wurde, gibt es keinen Weg zurück. Bitte sei vorsichtig. settings.delete_notices_1=- Diese Operation kann NICHT rückgängig gemacht werden. settings.deletion_success=Das Repository wurde gelöscht. settings.update_settings_success=Repository Einstellungen wurden aktualisiert. @@ -855,12 +911,16 @@ settings.delete_collaborator=Entfernen settings.collaborator_deletion=Mitarbeiter entfernen settings.remove_collaborator_success=Der Mitarbeiter wurde entfernt. settings.search_user_placeholder=Benutzer suchen… +settings.org_not_allowed_to_be_collaborator=Organisationen können nicht als Mitarbeiter hinzugefügt werden. +settings.user_is_org_member=Der Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden. settings.add_webhook=Webhook hinzufügen settings.webhook_deletion=Webhook löschen +settings.webhook_deletion_success=Webhook wurde entfernt. settings.webhook.test_delivery=Senden testen settings.webhook.request=Anfrage settings.webhook.response=Antwort settings.webhook.headers=Kopfzeilen +settings.webhook.payload=Inhalt settings.webhook.body=Inhalt settings.githook_edit_desc=Wenn ein Hook nicht aktiv ist, wird der Standardinhalt benutzt. Lasse den Inhalt leer, um den Hook zu deaktivieren. settings.githook_name=Hook-Name @@ -873,6 +933,8 @@ settings.slack_icon_url=Icon-URL settings.discord_username=Benutzername settings.discord_icon_url=Icon-URL settings.slack_color=Farbe +settings.event_send_everything=Alle Events +settings.event_choose=Benutzerdefinierte Events… settings.event_create=Erstellen settings.event_create_desc=Branch oder Tag erstellt. settings.event_pull_request=Pull-Request @@ -881,7 +943,10 @@ settings.event_push=Push settings.event_push_desc=Git push in ein Repository. settings.event_repository=Repository settings.event_repository_desc=Repository erstellt oder gelöscht. +settings.add_hook_success=Webhook wurde hinzugefügt. settings.update_webhook=Webhook aktualisieren +settings.update_hook_success=Webhook wurde aktualisiert. +settings.delete_webhook=Webhook entfernen settings.recent_deliveries=Letzte Zustellungen settings.hook_type=Hook Typ settings.slack_token=Token @@ -889,6 +954,7 @@ settings.slack_domain=Domain settings.slack_channel=Kanal settings.deploy_keys=Deploy-Schlüssel settings.add_deploy_key=Deploy-Schlüssel hinzufügen +settings.is_writable=Erlaube Schreibzugriff settings.title=Titel settings.deploy_key_content=Inhalt settings.branches=Branches @@ -896,10 +962,15 @@ settings.protected_branch=Branch-Protection settings.protected_branch_can_push=Push erlauben? settings.protected_branch_can_push_yes=Du kannst pushen settings.protected_branch_can_push_no=Du kannst nicht pushen +settings.branch_protection=Branch-Schutz" für Branch '%s' +settings.protect_this_branch=Brach-Schutz aktivieren +settings.protect_whitelist_search_users=Benutzer suchen… settings.protect_whitelist_search_teams=Suche nach Teams… settings.add_protected_branch=Schutz aktivieren settings.delete_protected_branch=Schutz deaktivieren +settings.protected_branch_deletion=Brach-Schutz deaktivieren settings.choose_branch=Wähle eine Branch… +settings.no_protected_branch=Es gibt keine geschützten Branches. diff.browse_source=Quellcode durchsuchen diff.parent=Ursprung @@ -955,6 +1026,9 @@ branch.create_from=von '%s' branch.create_success=Branch '%s' wurde erstellt. branch.branch_already_exists=Branch '%s' existiert bereits in diesem Repository. branch.deleted_by=Von %s gelöscht +branch.restore_success=Branch '%s' wurde wiederhergestellt. +branch.restore_failed=Wiederherstellung der Branch '%s' fehlgeschlagen. +branch.protected_deletion_failed=Branch '%s' ist geschützt und kann nicht gelöscht werden. topic.manage_topics=Themen verwalten topic.done=Fertig @@ -962,6 +1036,7 @@ topic.done=Fertig [org] org_name_holder=Name der Organisation org_full_name_holder=Vollständiger Name der Organisation +org_name_helper=Organisationsnamen sollten kurz und einprägsam sein. create_org=Organisation erstellen repo_updated=Aktualisiert people=Personen @@ -973,8 +1048,12 @@ create_team=Team erstellen org_desc=Beschreibung team_name=Teamname team_desc=Beschreibung +team_name_helper=Teamnamen sollten kurz und einprägsam sein. team_permission_desc=Berechtigungen +team_unit_desc=Zugriff auf Repositorybereiche erlauben +form.name_reserved=Der Organisationsname '%s' ist reserviert. +form.create_org_not_allowed=Du bist nicht berechtigt eine Organisation zu erstellen. settings=Einstellungen settings.options=Organisation @@ -983,12 +1062,17 @@ settings.website=Webseite settings.location=Standort settings.update_settings=Einstellungen speichern settings.update_setting_success=Organisationseinstellungen wurden aktualisiert. +settings.update_avatar_success=Der Organisationsavatar wurde aktualisiert. settings.delete=Organisation löschen settings.delete_account=Diese Organisation löschen settings.confirm_delete_account=Löschen +settings.delete_org_title=Organisation löschen +settings.delete_org_desc=Diese Organisation wird dauerhaft gelöscht. Fortfahren? settings.hooks_desc=Webhooks hinzufügen, die für alle Repositories dieser Organisation ausgelöst werden. members.membership_visibility=Sichtbarkeit der Mitgliedschaft: +members.public=Sichtbar +members.private_helper=sichtbar machen members.member_role=Mitgliedsrolle: members.owner=Besitzer members.member=Mitglied @@ -1000,12 +1084,17 @@ members.invite_now=Jetzt einladen teams.join=Beitreten teams.leave=Verlassen teams.read_access=Lesezugriff +teams.read_access_helper=Mitglieder können Teamrepositories ansehen und klonen. teams.write_access=Schreibzugriff +teams.admin_access=Administratorzugang +teams.admin_access_helper=Mitglieder können auf Team Repositories "pushen", von ihnen "pullen" und Mitarbeiter hinzufügen. teams.no_desc=Dieses Team hat keine Beschreibung teams.settings=Einstellungen teams.members=Teammitglieder teams.update_settings=Einstellungen aktualisieren +teams.delete_team=Team löschen teams.add_team_member=Teammitglied hinzufügen +teams.delete_team_title=Team löschen teams.delete_team_success=Das Team wurde gelöscht. teams.repositories=Team-Repositories teams.search_repo_placeholder=Repository durchsuchen… @@ -1015,6 +1104,7 @@ teams.add_nonexistent_repo=Das Repository, das du hinzufügen möchten, existier [admin] dashboard=Dashboard +users=Benutzerkonten organizations=Organisationen repositories=Repositories authentication=Authentifizierungsquellen @@ -1043,6 +1133,7 @@ dashboard.git_gc_repos_success=Alle Repositories haben Garbage Collection beende dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen dashboard.reinit_missing_repos_success=Alle verlorenen Git-Repositories mit existierenden Einträgen wurden erfolgreich aktualisiert. dashboard.sync_external_users=Externe Benutzerdaten synchronisieren +dashboard.sync_external_users_started=Externe Benutzersynchronisation gestartet. dashboard.git_fsck=Healthchecks auf alle Repositories ausführen dashboard.server_uptime=Server-Uptime dashboard.current_goroutine=Aktuelle Goroutinen @@ -1081,13 +1172,23 @@ users.activated=Aktiviert users.admin=Administrator users.repos=Repositories users.created=Registriert am +users.last_login=Letzte Anmeldung +users.new_success=Der Account '%s' wurde erstellt. users.edit=Bearbeiten users.auth_source=Authentifizierungsquelle users.local=Lokal +users.update_profile_success=Der Account '%s' wurde aktualisiert. users.edit_account=Benutzerkonto bearbeiten +users.max_repo_creation=Maximale Anzahl Repositories +users.max_repo_creation_desc=(Gib -1 ein, um das globale Standardlimit zu verwenden.) +users.is_activated=Account ist aktiviert users.is_admin=Ist Administrator +users.allow_git_hook=Darf "Git Hooks" erstellen +users.allow_import_local=Darf lokale Repositories importieren +users.allow_create_organization=Darf Organisationen erstellen users.update_profile=Benutzerkonto aktualisieren users.delete_account=Benutzerkonto löschen +users.deletion_success=Der Account wurde gelöscht. orgs.org_manage_panel=Organisationsverwaltung orgs.name=Name @@ -1104,6 +1205,7 @@ repos.stars=Favoriten repos.issues=Issues repos.size=Größe +auths.auth_manage_panel=Authentifikationsquellen verwalten auths.new=Authentifizierungsquelle hinzufügen auths.name=Name auths.type=Typ @@ -1121,6 +1223,9 @@ auths.bind_password=Passwort binden auths.user_base=Basis für Benutzersuche auths.user_dn=Benutzer DN auths.attribute_username=Benutzername Attribut +auths.attribute_name=Vornamensattribut +auths.attribute_surname=Nachnamensattribut +auths.attribute_mail=E-Mail Attribut auths.filter=Benutzerfilter auths.admin_filter=Admin Filter auths.ms_ad_sa=MS AD Suchattribute @@ -1149,12 +1254,27 @@ auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook. auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth Anwendung. auths.tip.gitlab=Erstelle unter https://gitlab.com/profile/applications eine neue Anwendung. auths.tip.openid_connect=Benutze die OpenID Connect Discovery URL (/.well-known/openid-configuration) als Endpunkt. +auths.edit=Authentifikationsquelle bearbeiten +auths.activated=Diese Authentifikationsquelle ist aktiviert auths.new_success=Die Authentifizierung "%s" wurde hinzugefügt. +auths.update_success=Diese Authentifizierungsquelle wurde aktualisiert. +auths.update=Authentifizierungsquelle aktualisieren +auths.delete=Authentifikationsquelle löschen auths.delete_auth_title=Authentifizierungsquelle löschen +auths.delete_auth_desc=Das Löschen einer Authentifizierungsquelle verhindert, dass Benutzer sich darüber anmelden können. Fortfahren? +auths.still_in_used=Diese Authentifizierungsquelle wird noch verwendet. Bearbeite oder lösche zuerst alle Benutzer, die diese Authentifizierungsquelle benutzen. +auths.deletion_success=Die Authentifizierungsquelle '%s' wurde gelöscht. +auths.login_source_exist=Die Authentifizierungsquelle '%s' existiert bereits. config.server_config=Serverkonfiguration +config.app_name=Seitentitel +config.app_ver=Gitea Version +config.app_url=Gitea Basis-URL config.custom_conf=Konfigurations-Datei-Pfad +config.domain=SSH Server-Domain +config.offline_mode=Lokaler Modus config.disable_router_log=Router-Log deaktivieren +config.run_user=Ausführen als config.run_mode=Laufzeit-Modus config.git_version=Git Version config.repo_root_path=Repository-Verzeichnis @@ -1187,16 +1307,26 @@ config.db_path=Verzeichnis config.db_path_helper=(für "sqlite3" und "tidb") config.service_config=Service-Konfiguration +config.register_email_confirm=E-Mail-Bestätigung benötigt zum Registrieren +config.disable_register=Selbstegistrierung deaktivieren +config.enable_openid_signup=OpenID Selbstregistrierung aktivieren +config.enable_openid_signin=OpenID Anmeldung aktivieren config.show_registration_button=Schaltfläche zum Registrieren anzeigen +config.require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich +config.mail_notify=E-Mail-Benachrichtigungen aktivieren config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren +config.enable_captcha=CAPTCHA aktivieren config.active_code_lives=Aktivierungscode Lebensdauer config.reset_password_code_lives=Ablaufdatum des Passworts zurücksetzen +config.default_keep_email_private=E-Mail-Adressen standardmäßig verbergen +config.enable_timetracking=Zeiterfassung aktivieren config.webhook_config=Webhook-Konfiguration config.queue_length=Warteschlangenlänge config.deliver_timeout=Zeitlimit für Zustellung config.skip_tls_verify=TLS Verifikation überspringen +config.mailer_config=SMTP Mailer Konfiguration config.mailer_enabled=Aktiviert config.mailer_disable_helo=HELO Deaktivieren config.mailer_name=Name @@ -1204,6 +1334,10 @@ config.mailer_host=Host config.mailer_user=Benutzer config.mailer_use_sendmail=Sendmail benutzen config.mailer_sendmail_path=Sendmail-Pfad +config.mailer_sendmail_args=Zusätzliche Argumente für Sendmail +config.send_test_mail=Test-E-Mail senden +config.test_mail_failed=Das Senden der Test-E-Mail an '%s' ist fehlgeschlagen: %v +config.test_mail_sent=Eine Test-E-Mail wurde an '%s' gesendet. config.oauth_config=OAuth-Konfiguration config.oauth_enabled=Aktiviert @@ -1307,6 +1441,8 @@ raw_seconds=Sekunden raw_minutes=Minuten [dropzone] +default_message=Zum Hochladen hier klicken oder Datei ablegen. +invalid_input_type=Dateien dieses Dateityps können nicht hochgeladen werden. file_too_big=Dateigröße ({{filesize}} MB) überschreitet die Maximalgröße ({{maxFilesize}} MB). remove_file=Datei entfernen @@ -1314,6 +1450,8 @@ remove_file=Datei entfernen notifications=Nachrichten unread=Ungelesen read=Gelesen +no_unread=Keine ungelesenen Benachrichtigungen. +no_read=Keine gelesenen Benachrichtigungen. pin=Benachrichtigung pinnen mark_as_read=Als gelesen markieren mark_as_unread=Als ungelesen markieren @@ -1326,4 +1464,6 @@ error.no_gpg_keys_found=Es konnte kein GPG-Schlüssel zu dieser Signatur gefunde error.not_signed_commit=Kein signierter Commit [units] +error.no_unit_allowed_repo=Du hast keine Berechtigung auf einen Bereich dieses Repositories zuzugreifen. +error.unit_not_allowed=Du hast keine Berechtigung auf diesen Repository-Bereich zuzugreifen. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 03078ccf975..07ac004d4cb 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -85,7 +85,7 @@ err_empty_admin_password = The administrator password cannot be empty. general_title = General Settings app_name = Site Title -app_name_helper = Enter your company name here. +app_name_helper = You can enter your company name here. repo_path = Repository Root Path repo_path_helper = Remote Git repositories will be saved to this directory. lfs_path = Git LFS Root Path @@ -121,6 +121,7 @@ federated_avatar_lookup = Enable Federated Avatars federated_avatar_lookup_popup = Enable federated avatar lookup using Libravatar. disable_registration = Disable Self-Registration disable_registration_popup = Disable user self-registration. Only administrators will be able to create new user accounts. +allow_only_external_registration_popup=Enable the registration only through external services. openid_signin = Enable OpenID Sign-In openid_signin_popup = Enable user sign-in via OpenID. openid_signup = Enable OpenID Self-Registration @@ -628,9 +629,9 @@ issues.new.no_milestone = No Milestone issues.new.clear_milestone = Clear milestone issues.new.open_milestone = Open Milestones issues.new.closed_milestone = Closed Milestones -issues.new.assignee = Assignee -issues.new.clear_assignee = Clear assignee -issues.new.no_assignee = No assignee +issues.new.assignees = Assignees +issues.new.clear_assignees = Clear assignees +issues.new.no_assignees = Nobody assigned issues.no_ref = No Branch/Tag Specified issues.create = Create Issue issues.new_label = New Label @@ -743,15 +744,15 @@ issues.cancel_tracking = Cancel issues.cancel_tracking_history = `cancelled time tracking %s` issues.time_spent_total = Total Time Spent issues.time_spent_from_all_authors = `Total Time Spent: %s` -issues.due_date = Due date -issues.invalid_due_date_format = "Due date format is invalid, must be 'yyyy-mm-dd'." -issues.error_modifying_due_date = "An error occured while modifying the due date." -issues.error_removing_due_date = "An error occured while remvoing the due date." -issues.due_date_form = "Due date, format yyyy-mm-dd" +issues.due_date = Due Date +issues.invalid_due_date_format = "Due date format must be 'yyyy-mm-dd'." +issues.error_modifying_due_date = "Failed to modify the due date." +issues.error_removing_due_date = "Failed to remove the due date." +issues.due_date_form = "yyyy-mm-dd" issues.due_date_form_add = "Add due date" issues.due_date_form_update = "Update due date" issues.due_date_form_remove = "Remove due date" -issues.due_date_not_writer = "You need to have at least write access to this repository in order to update the due date for this issue." +issues.due_date_not_writer = "You need repository write access to update an issue's due date." issues.due_date_not_set = "No due date set." issues.due_date_added = "added the due date %s %s" issues.due_date_modified = "modified the due date to %s from %s %s" @@ -1369,8 +1370,8 @@ auths.attribute_name = First Name Attribute auths.attribute_surname = Surname Attribute auths.attribute_mail = Email Attribute auths.attributes_in_bind = Fetch Attributes in Bind DN Context -auths.use_paged_search = Use paged search -auths.search_page_size = Page size +auths.use_paged_search = Use Paged Search +auths.search_page_size = Page Size auths.filter = User Filter auths.admin_filter = Admin Filter auths.ms_ad_sa = MS AD Search Attributes @@ -1459,6 +1460,7 @@ config.db_path_helper = (for "sqlite3" and "tidb") config.service_config = Service Configuration config.register_email_confirm = Require Email Confirmation to Register config.disable_register = Disable Self-Registration +config.allow_only_external_registration = Enable the registration only through external services config.enable_openid_signup = Enable OpenID Self-Registration config.enable_openid_signin = Enable OpenID Sign-In config.show_registration_button = Show Register Button diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index c08c059d5e9..8dd392af338 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -335,9 +335,6 @@ issues.new.no_milestone=Sin Milestone issues.new.clear_milestone=Limpiar Milestone issues.new.open_milestone=Milestones abiertas issues.new.closed_milestone=Milestones cerradas -issues.new.assignee=Asignado a -issues.new.clear_assignee=Limpiar asignado -issues.new.no_assignee=Sin asignado issues.create=Crear incidencia issues.new_label=Nueva Etiqueta issues.create_label=Crear etiqueta diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 3b878f49bc6..00d88467682 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -261,9 +261,6 @@ issues.new.no_milestone=Ei merkkipaalua issues.new.clear_milestone=Tyhjennä merkkipaalu issues.new.open_milestone=Avoimet merkkipaalut issues.new.closed_milestone=Suljetut merkkipaalut -issues.new.assignee=Osoitettu -issues.new.clear_assignee=Tyhjennä osoitettu -issues.new.no_assignee=Ei osoitettua issues.create=Ilmoita ongelma issues.new_label=Uusi tunniste issues.create_label=Luo tunniste diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index f398a210f08..f2fc5bcff0e 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -340,9 +340,6 @@ issues.new.no_milestone=Aucun jalon issues.new.clear_milestone=Effacer le jalon issues.new.open_milestone=Ouvrir un jalon issues.new.closed_milestone=Jalons fermés -issues.new.assignee=Affecté à -issues.new.clear_assignee=Supprimer les assignataires -issues.new.no_assignee=Pas d'assignataire issues.no_ref=Aucune branche/tag spécifiés issues.create=Créer un ticket issues.new_label=Nouvelle étiquette diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index f9dff831f85..ea6c58b6222 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -347,9 +347,6 @@ issues.new.no_milestone=Nincs mérföldkő issues.new.clear_milestone=Mérföldkő eltávolítása issues.new.open_milestone=Nyitott mérföldkövek issues.new.closed_milestone=Lezárt mérföldkövek -issues.new.assignee=Megbízott -issues.new.clear_assignee=Megbízott eltávolítása -issues.new.no_assignee=Nincs megbízott issues.no_ref=Nincsen ág/címke megadva issues.create=Hibajegy létrehozása issues.new_label=Új címke diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 90fcc9ed7f7..b8bd04e922d 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -340,9 +340,6 @@ issues.new.no_milestone=Tidak Ada Milestone issues.new.clear_milestone=Bersihkan milestone issues.new.open_milestone=Buka Milestone issues.new.closed_milestone=Tutup Milestone -issues.new.assignee=Menerima -issues.new.clear_assignee=Jelas menerima -issues.new.no_assignee=Tidak ada penerima issues.no_ref=Tidak Ada Cabang/Tag Ditentukan issues.create=Buat Masalah issues.new_label=Label Baru diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index d4afc7b4246..298d2cd1385 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -323,9 +323,6 @@ issues.new.no_milestone=Nessuna milestone issues.new.clear_milestone=Milestone pulita issues.new.open_milestone=Apri Milestone issues.new.closed_milestone=Milestone chiuse -issues.new.assignee=Assegnatario -issues.new.clear_assignee=Cancella l'assegnatario -issues.new.no_assignee=Nessun assegnatario issues.create=Crea Problema issues.new_label=Nuova etichetta issues.create_label=Crea Etichetta diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index fb575961d46..3328c194e7d 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -347,9 +347,6 @@ issues.new.no_milestone=マイルストーンなし issues.new.clear_milestone=マイルストーンをクリア issues.new.open_milestone=オープン中のマイルストーン issues.new.closed_milestone=クローズされたマイルストーン -issues.new.assignee=担当者 -issues.new.clear_assignee=担当者をクリア -issues.new.no_assignee=担当者なし issues.no_ref=ブランチ/タグが指定されていません issues.create=問題を作成 issues.new_label=新しいラベル diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 45ed6792742..5d0bf74e85c 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -323,9 +323,6 @@ issues.new.no_milestone=마일스톤 없음 issues.new.clear_milestone=마일스톤 초기화 issues.new.open_milestone=마일스톤 생성 issues.new.closed_milestone=마일스톤 닫기 -issues.new.assignee=담당자 -issues.new.clear_assignee=담당자 초기화 -issues.new.no_assignee=담당자 없음 issues.no_ref=Branch/Tag 가 지정되어 있지 않습니다. issues.create=이슈 생성 issues.new_label=새로운 레이블 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 6d91d7d0748..e6b2e4ddb40 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -347,9 +347,6 @@ issues.new.no_milestone=Nav atskaites punktu issues.new.clear_milestone=Notīrīt atskaites punktus issues.new.open_milestone=Atvērtie atskaites punktus issues.new.closed_milestone=Aizvērtie atskaites punkti -issues.new.assignee=Atbildīgais -issues.new.clear_assignee=Noņemt atbildīgo -issues.new.no_assignee=Nav atbildīgā issues.no_ref=Nav norādīts atzars/tags issues.create=Pieteikt problēmu issues.new_label=Jauna etiķete diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 3278eaca813..7b2d4f12690 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -345,9 +345,6 @@ issues.new.no_milestone=Geen mijlpaal issues.new.clear_milestone=Verwijder mijlpaal issues.new.open_milestone=Open mijlpalen issues.new.closed_milestone=Gesloten mijlpalen -issues.new.assignee=Toegewezen aan -issues.new.clear_assignee=Verwijder verantwoordelijke -issues.new.no_assignee=Geen verantwoordelijke issues.no_ref=Geen Branch/Tag gespecificeerd issues.create=Maak probleem issues.new_label=Nieuw Label diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 1818547efe4..e2a01ad6952 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -340,9 +340,6 @@ issues.new.no_milestone=Brak kamienia milowego issues.new.clear_milestone=Wyczyść kamień milowy issues.new.open_milestone=Otwórz kamienie milowe issues.new.closed_milestone=Zamknięte kamienie milowe -issues.new.assignee=Przypisany -issues.new.clear_assignee=Usuń przypisanie -issues.new.no_assignee=Brak przypisania issues.no_ref=Nie określono gałęzi/etykiety issues.create=Utwórz problem issues.new_label=Nowa etykieta diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index d0de25b2da4..a6c11cee9ca 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -81,7 +81,7 @@ err_empty_admin_password=A senha do administrador não pode ser em branco. general_title=Configurações gerais app_name=Título do site -app_name_helper=Digite o nome da sua empresa aqui. +app_name_helper=Você pode inserir o nome da empresa aqui. repo_path=Caminho raíz do repositório repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório. lfs_path=Caminho raiz do Git LFS @@ -331,6 +331,7 @@ change_username=Seu nome de usuário foi alterado. change_username_prompt=Nota: as alterações de nome de usuário também mudam sua URL da conta. continue=Continuar cancel=Cancelar +language=Idioma lookup_avatar_by_mail=Procure o avatar do endereço de e-mail federated_avatar_lookup=Busca de avatar federativo @@ -623,9 +624,9 @@ issues.new.no_milestone=Sem marco issues.new.clear_milestone=Limpar marco issues.new.open_milestone=Marcos abertos issues.new.closed_milestone=Marcos fechados -issues.new.assignee=Responsável -issues.new.clear_assignee=Limpar responsável -issues.new.no_assignee=Não atribuída +issues.new.assignees=Responsáveis +issues.new.clear_assignees=Limpar responsáveis +issues.new.no_assignees=Nenhum responsável issues.no_ref=Nenhum branch/tag especificado issues.create=Criar issue issues.new_label=Nova etiqueta @@ -739,14 +740,14 @@ issues.cancel_tracking_history=`cancelou contador de tempo %s` issues.time_spent_total=Tempo total gasto issues.time_spent_from_all_authors=`Tempo total gasto: %s` issues.due_date=Data limite -issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'aaaa-mm-dd'. -issues.error_modifying_due_date=Ocorreu um erro ao modificar a data limite. -issues.error_removing_due_date=Ocorreu um erro ao remover a data limite. -issues.due_date_form=Data limite, formato aaaa-mm-dd +issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'dd/mm/aaaa'. +issues.error_modifying_due_date=Falha ao modificar a data limite. +issues.error_removing_due_date=Falha ao remover a data limite. +issues.due_date_form=dd/mm/aaaa issues.due_date_form_add=Adicionar data limite issues.due_date_form_update=Modificar data limite issues.due_date_form_remove=Remover data limite -issues.due_date_not_writer=Você precisa ter pelo menos permissão de escrita neste repositório para atualizar a data limite desta issue. +issues.due_date_not_writer=Você deve ter permissão de escrita no repositório para atualizar a data limite de uma issue. issues.due_date_not_set=Data limite não informada. issues.due_date_added=adicionou a data limite %s à %s issues.due_date_modified=modificou a data limite para %s ao invés de %s à %s @@ -798,7 +799,7 @@ milestones.title=Título milestones.desc=Descrição milestones.due_date=Prazo (opcional) milestones.clear=Limpar -milestones.invalid_due_date_format=Formato da data limite deve ser 'aaaa-mm-dd'. +milestones.invalid_due_date_format=Formato da data limite deve ser 'dd/mm/aaaa'. milestones.create_success=O marco '%s' foi criado. milestones.edit=Editar marco milestones.edit_subheader=Marcos organizam as issues e acompanham o progresso. @@ -1351,6 +1352,8 @@ auths.attribute_name=Atributo primeiro nome auths.attribute_surname=Atributo sobrenome auths.attribute_mail=Atributo e-mail auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN +auths.use_paged_search=Use a pesquisa paginada +auths.search_page_size=Tamanho da página auths.filter=Filtro de usuário auths.admin_filter=Filtro de administrador auths.ms_ad_sa=Atributos de pesquisa do MS AD diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index eb1bab25b67..7baca9ee898 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -475,9 +475,6 @@ issues.new.no_milestone=Нет этапа issues.new.clear_milestone=Очистить этап issues.new.open_milestone=Открыть этап issues.new.closed_milestone=Завершенные этапы -issues.new.assignee=Ответственный -issues.new.clear_assignee=Убрать ответственного -issues.new.no_assignee=Нет ответственного issues.no_ref=Не указана ветка или тэг issues.create=Добавить задачу issues.new_label=Новая метка diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini index 5acf7904341..8c4fb331e61 100644 --- a/options/locale/locale_sr-SP.ini +++ b/options/locale/locale_sr-SP.ini @@ -270,9 +270,6 @@ issues.new.no_milestone=Нема фазе issues.new.clear_milestone=Уклони фазу issues.new.open_milestone=Отворене фазе issues.new.closed_milestone=Затворене фазе -issues.new.assignee=Одговорни -issues.new.clear_assignee=Уклони одговорног -issues.new.no_assignee=Нема одговорних issues.create=Додај задатак issues.new_label=Нова лабела issues.create_label=Креирај лабелу diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index a2ad878395e..a17f5add930 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -339,9 +339,6 @@ issues.new.no_milestone=Ingen Milsten issues.new.clear_milestone=Rensa milstenar issues.new.open_milestone=Öppna Milstenar issues.new.closed_milestone=Stängda Milstenar -issues.new.assignee=Förvärvare -issues.new.clear_assignee=Rensa förvärvare -issues.new.no_assignee=Ingen förvärvare issues.create=Skapa Ärende issues.new_label=Ny etikett issues.create_label=Skapa Etikett diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 7159f176364..10bf5f63403 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -338,9 +338,6 @@ issues.new.no_milestone=Kilometre Taşı Yok issues.new.clear_milestone=Kilometre Taşlarını Temizle issues.new.open_milestone=Kilometre Taşlarını Aç issues.new.closed_milestone=Kapanmış Kilometre Taşları -issues.new.assignee=Atanan -issues.new.clear_assignee=Atamayı Temizle -issues.new.no_assignee=Atanan Kişi Yok issues.no_ref=Bölüm/Etiket Belirtilmedi issues.create=Sorun Oluştur issues.new_label=Yeni Etiket diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index a6e3492e218..a4281beda06 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -11,7 +11,7 @@ sign_up=Реєстрація link_account=Прив'язати обліковий запис link_account_signin_or_signup=Увійдіть з уже існуючими обліковими даними або зареєструйтеся для зв'язку з цим аккаунтом. register=Реєстрація -website=Web-сайт +website=Веб-сайт version=Версія page=Сторінка template=Шаблон @@ -72,20 +72,28 @@ password=Пароль db_name=Ім'я бази даних ssl_mode=SSL path=Шлях +sqlite_helper=Шлях до файлу для бази даних SQLite3 або TiDB.
Введіть абсолютний шлях, якщо ви запускаєте Gitea як сервіс. err_empty_db_path=Шлях до бази даних SQLite3 або TiDB не може бути порожнім. +err_invalid_tidb_name=Ім'я бази даних TiDB не може містити символи '.' або '-'. no_admin_and_disable_registration=Ви не можете вимкнути реєстрацію до створення облікового запису адміністратора. +err_empty_admin_password=Пароль адміністратора не може бути порожнім. general_title=Загальні налаштування app_name=Назва сайту repo_path=Кореневий шлях репозиторія repo_path_helper=Всі вилучені Git репозиторії будуть збережені в цей каталог. lfs_path=Кореневої шлях Git LFS -lfs_path_helper=У цій папці будуть зберігатися файли Git LFS. Залиште порожнім, щоб відключити LFS. +lfs_path_helper=У цій папці будуть зберігатися файли Git LFS. Залиште порожнім, щоб вимкнути LFS. +run_user=Запуск від імені Користувача +run_user_helper=Введіть ім'я користувача операційної системи, під яким працює Gitea. Зверніть увагу, що цей користувач повинен бути доступ до кореневого шляху репозиторія. domain=Домен SSH сервера ssh_port=Порт SSH сервера -ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб відключити SSH. +ssh_port_helper=Номер порту, який використовує SSH сервер. Залиште порожнім, щоб вимкнути SSH. +http_port=Gitea HTTP порт +http_port_helper=Номер порту, який буде прослуховуватися Giteas веб-сервером. app_url=Базова URL-адреса Gitea log_root_path=Шлях до лог файлу +log_root_path_helper=Файли журналу будуть записані в цей каталог. optional_title=Додаткові налаштування email_title=Налаштування Email @@ -93,12 +101,20 @@ smtp_host=SMTP хост smtp_from=Відправляти Email від імені mailer_user=SMTP Ім'я кристувача mailer_password=SMTP Пароль -mail_notify=Дозволити поштові повідомлення +register_confirm=Потрібно підтвердити електронну пошту для реєстрації +mail_notify=Увімкнути сповіщення електронною поштою +offline_mode=Увімкнути локальний режим disable_gravatar=Вимкнути Gravatar +federated_avatar_lookup=Увімкнути федеративні аватари federated_avatar_lookup_popup=Увімкнути зовнішний Аватар за допомогою Libravatar. +disable_registration=Вимкнути самостійну реєстрацію +disable_registration_popup=Вимкнути самостійну реєстрацію користувачів, тільки адміністратор може створювати нові облікові записи. openid_signin=Увімкнути реєстрацію за допомогою OpenID +openid_signin_popup=Увімкнути вхід за допомогою OpenID. +openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID enable_captcha=Увімкнути CAPTCHA enable_captcha_popup=Вимагати перевірку CAPTCHA при самостійній реєстрації користувача. +admin_title=Налаштування облікового запису адміністратора admin_name=Ім'я кристувача Адміністратора admin_password=Пароль confirm_password=Підтвердження пароля @@ -107,8 +123,14 @@ install_btn_confirm=Встановлення Gitea test_git_failed=Не в змозі перевірити 'git' команду: %v save_config_failed=Не в змозі зберегти конфігурацію: %v install_success=Ласкаво просимо! Дякуємо вам за вибір Gitea. Розважайтеся, і будьте обережні! +default_keep_email_private=Приховати адресу електронної пошти за замовчуванням +default_keep_email_private_popup=Приховати адресу електронної пошти нових облікових записів за замовчуванням. +default_allow_create_organization=Дозволити створення організацій за замовчуванням +default_enable_timetracking=Увімкнути відстеження часу за замовчуванням +no_reply_address=Прихований поштовий домен [home] +uname_holder=Ім'я користувача або Ел. пошта password_holder=Пароль switch_dashboard_context=Змінити дошку my_repos=Мої репозиторії @@ -127,17 +149,20 @@ users=Користувачі organizations=Організації search=Пошук code=Код +repo_no_results=Відповідних репозиторіїв не знайдено. +code_search_results=Результати пошуку '%s' [auth] create_new_account=Реєстрація аккаунта register_helper_msg=Вже зареєстровані? Увійдіть зараз! disable_register_prompt=Вибачте, можливість реєстрації відключена. Будь ласка, зв'яжіться з адміністратором сайту. +disable_register_mail=Підтвердження реєстрації електронною поштою вимкнено. remember_me=Запам'ятати мене forgot_password_title=Забув пароль forgot_password=Забули пароль? sign_up_now=Потрібен аккаунт? Зареєструватися. -confirmation_mail_sent_prompt=Новий лист для підтвердження було направлено на %s, будь ласка, перевірте вашу поштову скриньку протягом% s для завершення реєстрації. -reset_password_mail_sent_prompt=Лист для підтвердження було направлено на %s. Будь ласка, перевірте вашу поштову скриньку протягом% s для скидання пароля. +confirmation_mail_sent_prompt=Новий лист для підтвердження було відправлено на %s, будь ласка, перевірте вашу поштову скриньку протягом %s для завершення реєстрації. +reset_password_mail_sent_prompt=Лист для підтвердження було відправлено на %s. Будь ласка, перевірте вашу поштову скриньку протягом %s для скидання пароля. active_your_account=Активувати обліковий запис prohibit_login=Вхід заборонений prohibit_login_desc=Вхід для вашого профілю був заборонений, будь ласка, зв'яжіться з адміністратором сайту. @@ -197,22 +222,33 @@ TreeName=Шлях до файлу Content=Зміст require_error=` не може бути пустим.` -git_ref_name_error=` має бути правильним посилальним ім'ям Git.` +git_ref_name_error=` повинен бути правильним посилальним ім'ям Git.` +size_error=` повинен бути розмір %s.` +min_size_error=` повинен бути принаймні %s символів.` +max_size_error=` повинен бути не більш як %s символів.` email_error=` не є адресою електронної пошти.` +url_error=` не є припустимою URL-Адресою.` +include_error=`повинен бути текст '%s'` unknown_error=Невідома помилка: +captcha_incorrect=Код CAPTCHA неправильний. password_not_match=Паролі не співпадають. username_been_taken=Ім'я користувача вже зайнято. repo_name_been_taken=Ім'я репозіторію вже використовується. +org_name_been_taken=Назва організації вже зайнято. +team_name_been_taken=Назва команди вже зайнято. email_been_used=Ця електронна адреса вже використовується. +openid_been_used=OpenID адреса '%s' вже використовується. username_password_incorrect=Неправильне ім'я користувача або пароль. user_not_exist=Даний користувач не існує. auth_failed=Помилка автентифікації: %v +target_branch_not_exist=Цільової гілки не існує. [user] +change_avatar=Змінити свій аватар… join_on=Приєднався repositories=Репозиторії activity=Публічна активність @@ -241,34 +277,44 @@ uid=Ідентифікатор Uid public_profile=Загальнодоступний профіль full_name=Повне ім'я -website=Web-сайт +website=Веб-сайт location=Місцезнаходження update_profile=Оновити профіль update_profile_success=Профіль успішно оновлено. continue=Продовжити cancel=Відміна +language=Мова federated_avatar_lookup=Знайти зовнішній аватар enable_custom_avatar=Увімкнути користувацькі аватари choose_new_avatar=Оберіть новий аватар update_avatar=Оновити аватар delete_current_avatar=Видалити поточний аватар +update_avatar_success=Ваш аватар був змінений. change_password=Оновити пароль old_password=Поточний пароль new_password=Новий пароль retype_new_password=Введіть новий пароль ще раз +change_password_success=Ваш пароль був оновлений. Тепер увійдіть в систему, використовуючи новий пароль. +password_change_disabled=Нелокальні акаунти не можуть змінити пароль через Gitea. emails=Адреса електронної пошти manage_emails=Керування адресами ел. пошти email_desc=Ваша основна адреса електронної пошти використовуватиметься для сповіщення та інших операцій. primary=Основний +primary_email=Зробити основним delete_email=Видалити +add_new_email=Додати нову адресу електронної пошти +add_email=Додати адресу електронної пошти +keep_email_private=Приховати адресу електронної пошти +keep_email_private_popup=Вашу адресу електронної пошти буде приховано від інших користувачів. manage_ssh_keys=Керувати SSH ключами manage_gpg_keys=Керувати GPG ключами add_key=Додати ключ ssh_helper=Потрібна допомога? Дивіться гід на GitHub з генерації ключів SSH або виправлення типових неполадок SSH. +gpg_helper= Потрібна допомога? Перегляньте посібник GitHub про GPG . add_new_key=Додати SSH ключ add_new_gpg_key=Додати GPG ключ key_id=ID ключа @@ -277,6 +323,7 @@ key_content=Зміст delete_key=Видалити ssh_key_deletion=Видалити SSH ключ gpg_key_deletion=Видалити GPG ключ +gpg_key_deletion_desc=Видалення GPG ключа скасовує перевірку підписаних ним комітів. Продовжити? add_on=Додано valid_until=Дійсний до valid_forever=Дійсний завжди @@ -288,14 +335,18 @@ key_state_desc=Цей ключ використовувався в останн token_state_desc=Цей токен використовувався в останні 7 днів show_openid=Показати у профілю hide_openid=Не показувати у профілі +ssh_disabled=SSH вимкнено manage_social=Керувати зв'язаними аккаунтами соціальних мереж +unbind=Від'єднати generate_new_token=Згенерувати новий токен token_name=Ім'я токену generate_token=Згенерувати токен delete_token=Видалити +twofa_disable=Вимкнути двофакторну автентифікацію +or_enter_secret=Або введіть секрет: %s @@ -321,20 +372,28 @@ readme_helper=Виберіть шаблон README. create_repo=Створити репозиторій default_branch=Головна гілка mirror_prune=Очистити +mirror_interval=Інтервал дзеркалювання (доступні значення 'h', 'm', 's') +mirror_address=Клонування з URL-адреси +mirror_last_synced=Остання синхронізація watchers=Спостерігачі forks=Форки pick_reaction=Залиште свою оцінку form.reach_limit_of_creation=Ви досягли максимальної кількості %d створених репозиторіїв. +need_auth=Клонування авторизації migrate_type=Тип міграції migrate_type_helper=Даний репозиторій буде дзеркалом migrate_repo=Перенесення репозиторія +migrate.clone_address=Міграція / клонувати з URL-адреси +migrate.clone_address_desc=URL-адреса HTTP(S) або Git "clone" існуючого репозиторія migrate.failed=Міграція не вдалася: %v +migrate.lfs_mirror_unsupported=Дзеркалювання LFS об'єктів не підтримується - використовуйте 'git lfs fetch --all' і 'git lfs push --all' вручну. mirror_from=дзеркало forked_from=форк від copy_link=Копіювати +copy_link_error=Натисніть ⌘-C або Ctrl-C, щоб скопіювати copied=Скопійовано unwatch=Не стежити watch=Слідкувати @@ -368,13 +427,16 @@ file_history=Історія file_view_raw=Перегляд Raw file_permalink=Постійне посилання stored_lfs=Збережено з Git LFS +commit_graph=Графік комітів editor.new_file=Новий файл editor.upload_file=Завантажити файл editor.edit_file=Редагування файлу editor.preview_changes=Попередній перегляд змін editor.edit_this_file=Редагувати файл +editor.must_be_on_a_branch=Ви повинні бути у гілці щоб зробити, або запропонувати зміни до цього файлу. editor.delete_this_file=Видалити файл +editor.must_have_write_access=Ви повинні мати доступ на запис щоб запропонувати зміни до цього файлу. editor.name_your_file=Дайте назву файлу… editor.or=або editor.cancel_lower=Скасувати @@ -383,13 +445,17 @@ editor.add_tmpl=Додати '%s/' editor.add=Додати '%s' editor.update=Оновити '%s' editor.delete=Видалити '%s' +editor.commit_message_desc=Додати необов'язковий розширений опис… +editor.commit_directly_to_this_branch=Зробіть коміт прямо в гілку %s. editor.create_new_branch=Створити нову гілку для цього коміту та відкрити запит на злиття. -editor.new_branch_name_desc=Нова назва гілки… +editor.new_branch_name_desc=Ім'я нової гілки… editor.cancel=Відміна editor.branch_already_exists=Гілка '%s' вже присутня в репозиторії. +editor.fail_to_update_file=Не вдалося оновити/створити файл '%s' через помилку: %v editor.upload_files_to_dir=Завантажувати файли до '%s' commits.commits=Коміти +commits.search=Знайти коміт… commits.find=Пошук commits.search_all=Усі гілки commits.author=Автор @@ -398,27 +464,32 @@ commits.date=Дата commits.older=Давніше commits.newer=Новіше +ext_issues=Зов. Проблеми -issues.new=Нова Проблема +issues.new=Нова проблема issues.new.labels=Мітки -issues.new.no_label=Без Мітки +issues.new.no_label=Без мітки issues.new.clear_labels=Очистити мітки issues.new.milestone=Етап issues.new.no_milestone=Етап відсутній issues.new.clear_milestone=Очистити етап issues.new.open_milestone=Активні етапи issues.new.closed_milestone=Закриті етапи -issues.new.assignee=Виконавець -issues.new.clear_assignee=Прибрати виконавеця -issues.new.no_assignee=Немає виконавеця -issues.create=Створити Проблему +issues.new.assignees=Виконавеці +issues.new.clear_assignees=Прибрати виконавеців +issues.no_ref=Не вказана гілка або тег +issues.create=Створити проблему issues.new_label=Нова мітка issues.new_label_placeholder=Назва мітки issues.new_label_desc_placeholder=Опис issues.create_label=Створити мітку issues.label_templates.helper=Оберіть набір міток issues.label_templates.fail_to_load_file=Не вдалося завантажити файл шаблона мітки '%s': %v +issues.add_label_at=додав(ла) мітку
%s
%s +issues.add_milestone_at=`додав(ла) до %s етапу %s` issues.deleted_milestone=`(видалено)` +issues.add_assignee_at=`був призначений %s %s` +issues.remove_assignee_at=`видалили із призначених %s` issues.open_tab=%d відкрито issues.close_tab=%d закрито issues.filter_label=Мітка @@ -453,7 +524,7 @@ issues.next=Далі issues.open_title=Відкрити issues.closed_title=Закриті issues.num_comments=%d коментарів -issues.commented_at=`відкоментовано %s` +issues.commented_at=`прокоментував(ла) %s` issues.delete_comment_confirm=Ви впевнені, що хочете видалити цей коментар? issues.no_content=Тут ще немає жодного змісту. issues.close_issue=Закрити @@ -493,7 +564,11 @@ issues.add_time_short=Додати час issues.add_time_cancel=Відміна issues.add_time_hours=Години issues.add_time_minutes=Хвилини +issues.add_time_sum_to_small=Час не введено. issues.cancel_tracking=Відміна +issues.due_date=Термін дії +issues.due_date_form_add=Додати дату завершення +issues.due_date_form_remove=Видалити дату завершення pulls.new=Новий запит на злиття pulls.compare_changes=Новий запит на злиття @@ -503,7 +578,9 @@ pulls.filter_branch=Фільтр по гілці pulls.no_results=Результатів не знайдено. pulls.create=Створити запит на злиття pulls.title_desc=хоче злити %[1]d комітів з %[2]s до %[3]s +pulls.tab_conversation=Обговорення pulls.tab_commits=Коміти +pulls.tab_files=Змінені файли pulls.reopen_to_merge=Будь ласка перевідкрийте цей запит щоб здіснити операцію злиття. pulls.merged=Злито pulls.can_auto_merge_desc=Цей запит можна об'єднати автоматично. @@ -525,6 +602,7 @@ milestones.edit=Редагувати етап milestones.cancel=Відміна milestones.modify=Оновити етап +ext_wiki=Зов. Wiki wiki=Wiki wiki.welcome=Ласкаво просимо до Wiki. @@ -533,6 +611,7 @@ wiki.page=Сторінка wiki.filter_page=Фільтр сторінок wiki.new_page=Сторінка wiki.save_page=Зберегти сторінку +wiki.last_commit_info=%s редагував цю сторінку %s wiki.edit_page_button=Редагувати wiki.new_page_button=Нова сторінка wiki.delete_page_button=Видалити сторінку @@ -546,15 +625,17 @@ activity.period.halfweekly=3 дні activity.period.weekly=1 тиждень activity.period.monthly=1 місяць activity.overview=Огляд +activity.active_prs_count_1=%d Активний запити на злиття activity.active_prs_count_n=%d Активні запити на злиття activity.merged_prs_count_1=Злитий запит на злиття activity.merged_prs_count_n=Злиті запити на злиття activity.opened_prs_count_1=Запропонований запит на злиття activity.opened_prs_count_n=Запропонованих запитів на злиття -activity.title.user_1=%d користувач -activity.title.user_n=%d користувачів +activity.title.user_1=%d користувачем +activity.title.user_n=%d користувачами activity.title.prs_1=%d Запит на злиття activity.title.prs_n=%d Запитів на злиття +activity.title.prs_merged_by=%s злито %s activity.title.prs_opened_by=%s запропоновано %s activity.merged_prs_label=Злито activity.opened_prs_label=Запропоновано @@ -564,8 +645,8 @@ activity.closed_issues_count_1=Закрита проблема activity.closed_issues_count_n=Закриті проблеми activity.title.issues_1=%d Проблема activity.title.issues_n=%d Проблеми -activity.title.issues_closed_by=%s закрито %s -activity.title.issues_created_by=%s створено %s +activity.title.issues_closed_by=%s закрита(і) %s +activity.title.issues_created_by=%s створена(і) %s activity.closed_issue_label=Закриті activity.new_issues_count_1=Нова Проблема activity.new_issues_count_n=%d Проблем @@ -573,7 +654,7 @@ activity.new_issue_label=Відкриті activity.unresolved_conv_label=Відкрити activity.title.releases_1=%d Реліз activity.title.releases_n=%d Релізів -activity.title.releases_published_by=%s Опубліковано %s +activity.title.releases_published_by=%s опубліковано %s activity.published_release_label=Опубліковано search=Пошук @@ -582,7 +663,7 @@ search.search_repo=Пошук репозиторію settings=Налаштування settings.options=Репозиторій settings.collaboration.admin=Адміністратор -settings.collaboration.write=Написати +settings.collaboration.write=Запис settings.collaboration.read=Читати settings.collaboration.undefined=Не визначено settings.hooks=Веб-хуки @@ -590,7 +671,7 @@ settings.githooks=Git хуки settings.basic_settings=Базові налаштування settings.mirror_settings=Налаштування дзеркала settings.sync_mirror=Синхронізувати зараз -settings.site=Web-сайт +settings.site=Веб-сайт settings.update_settings=Оновити налаштування settings.advanced_settings=Додаткові налаштування settings.wiki_desc=Увімкнути репозиторії Wiki @@ -598,14 +679,21 @@ settings.use_internal_wiki=Використовувати вбудовані Wik settings.use_external_wiki=Використовувати зовнішні Wiki settings.external_wiki_url=URL зовнішньої wiki settings.external_tracker_url=URL зовнішньої системи відстеження проблем +settings.tracker_url_format=Формат URL зовнішнього трекера задач settings.tracker_issue_style.numeric=Цифровий settings.tracker_issue_style.alphanumeric=Буквено-цифровий +settings.admin_settings=Налаштування адміністратора settings.danger_zone=Небезпечна зона settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою. Будь ласка, виберіть інше ім'я. -settings.transfer=Переказати новому власнику +settings.convert=Перетворити на звичайний репозиторій +settings.transfer=Передати новому власнику +settings.wiki_delete=Видалити Wiki-дані +settings.confirm_wiki_delete=Видалити Wiki-дані settings.delete=Видалити цей репозиторій settings.delete_notices_1=- Цю операцію НЕ МОЖНА відмінити. +settings.update_settings_success=Налаштування репозиторію було оновлено. settings.transfer_owner=Новий власник +settings.make_transfer=Здіснити перенесення settings.confirm_delete=Видалити репозиторій settings.delete_collaborator=Видалити settings.search_user_placeholder=Пошук користувача… @@ -626,6 +714,7 @@ settings.slack_icon_url=URL іконки settings.discord_username=Ім'я кристувача settings.discord_icon_url=URL іконки settings.slack_color=Колір +settings.event_send_everything=Всі події settings.event_create=Створити settings.event_create_desc=Гілку або тег створено. settings.event_pull_request=Запити до злиття @@ -639,7 +728,7 @@ settings.slack_domain=Домен settings.slack_channel=Канал settings.deploy_keys=Ключі для розгортування settings.add_deploy_key=Додати ключ для розгортування -settings.is_writable=Включити доступ для запису +settings.is_writable=Увімкнути доступ для запису settings.title=Заголовок settings.deploy_key_content=Зміст settings.branches=Гілки @@ -653,8 +742,11 @@ settings.delete_protected_branch=Вимкнути захист settings.choose_branch=Оберіть гілку… diff.browse_source=Переглянути джерело +diff.parent=джерело diff.commit=коміт +diff.show_diff_stats=Показати статистику Diff diff.show_split_view=Розділений перегляд +diff.show_unified_view=Об'єднаний перегляд diff.stats_desc= %d змінених файлів з %d додано та %d видалено diff.view_file=Переглянути файл diff.too_many_files=Деякі файли не було показано, через те що забагато файлів було змінено @@ -668,11 +760,14 @@ release.edit=редагувати release.ahead=%d комітів %s після цього релізу release.tag_name=Назва тегу release.target=Ціль +release.tag_helper=Виберіть існуючий тег або створіть новий. release.title=Заголовок release.content=Зміст +release.write=Запис release.preview=Переглянути release.loading=Завантаження… release.prerelease_desc=Позначити як пре-реліз +release.prerelease_helper=Позначте цей випуск непридатним для ПРОД використання. release.cancel=Відміна release.publish=Опублікувати реліз release.save_draft=Зберегти чернетку @@ -710,13 +805,17 @@ team_permission_desc=Права доступу settings=Налаштування settings.options=Організація settings.full_name=Повне ім'я -settings.website=Web-сайт +settings.website=Веб-сайт settings.location=Розташування settings.update_settings=Оновити налаштування settings.delete=Видалити організацію settings.delete_account=Видалити цю організацію settings.confirm_delete_account=Підтвердіть видалення +members.membership_visibility=Видимість учасника: +members.public_helper=зробити прихованим +members.private=Прихований +members.private_helper=зробити видимим members.member_role=Роль учасника: members.owner=Власник members.member=Учасник @@ -728,6 +827,8 @@ members.invite_now=Запросити зараз teams.join=Приєднатися teams.leave=Покинути teams.read_access=Доступ для читання +teams.write_access=Доступ на запис +teams.admin_access=Доступ адміністратора teams.settings=Налаштування teams.members=Учасники команди teams.update_settings=Оновити налаштування @@ -740,6 +841,7 @@ dashboard=Панель управління users=Облікові записи користувачів organizations=Організації repositories=Репозиторії +authentication=Джерела автентифікації config=Конфігурація notices=Сповіщення системи monitor=Моніторинг @@ -755,20 +857,40 @@ dashboard.delete_inactivate_accounts=Видалити всі неактивні dashboard.delete_inactivate_accounts_success=Усі неактивні облікові записи успішно видалено. dashboard.server_uptime=Uptime серверу dashboard.current_memory_usage=Поточне використання пам'яті +dashboard.total_memory_allocated=Виділено пам'яті загалом dashboard.memory_obtained=Отримано пам'яті dashboard.stack_memory_obtained=Зайнято пам'яті стеком dashboard.mspan_structures_usage=Використання структур MSpan +dashboard.mspan_structures_obtained=Отримано структур MSpan dashboard.mcache_structures_usage=Використання структур MCache dashboard.mcache_structures_obtained=Отримано структур MCache +dashboard.profiling_bucket_hash_table_obtained=Отримано хеш-таблиць профілювання +dashboard.gc_metadata_obtained=Отримано метаданих GC +dashboard.other_system_allocation_obtained=Отримання інших виділень пам'яті dashboard.next_gc_recycle=Наступний цикл GC +users.user_manage_panel=Керування обліковими записами користувачів +users.new_account=Створити обліковий запис users.name=Ім'я кристувача users.activated=Активовано users.admin=Адміністратор users.repos=Репозиторії users.created=Створено +users.last_login=Останній вхід +users.send_register_notify=Надіслати повідомлення про реєстрацію користувача users.edit=Редагувати +users.auth_source=Джерело автентифікації users.local=Локальні +users.max_repo_creation=Максимальна кількість репозиторіїв +users.max_repo_creation_desc=(Введіть -1, щоб використовувати глобальний ліміт за замовчуванням.) +users.is_activated=Обліковий запис користувача увімкнено +users.prohibit_login=Вимкнути вхід +users.is_admin=Адміністратор +users.allow_git_hook=Може створювати Git хуки +users.allow_import_local=Може імпортувати локальні репозиторії +users.allow_create_organization=Може створювати організацій +users.update_profile=Оновити обліковий запис +users.delete_account=Видалити цей обліковий запис orgs.org_manage_panel=Керування організаціями orgs.name=Назва @@ -780,9 +902,12 @@ repos.repo_manage_panel=Керування організаціями repos.owner=Власник repos.name=Назва repos.private=Приватний +repos.stars=В обраному repos.issues=Проблеми repos.size=Розмір +auths.auth_manage_panel=Керування джерелом аутентифікації +auths.new=Додати джерело автентифікації auths.name=Ім'я auths.type=Тип auths.enabled=Увімкнено @@ -807,11 +932,27 @@ auths.oauth2_profileURL=URL профілю auths.oauth2_emailURL=URL електронної пошти auths.enable_auto_register=Увімкнути автоматичну реєстрацію auths.tips=Поради +auths.tips.oauth2.general=OAuth2 аутентифікація +auths.tips.oauth2.general.tip=При додаванні нового OAuth2 провайдера, URL адреса переадресації по завершенні аутентифікації повинена виглядати так:/user/oauth2//callback +auths.tip.oauth2_provider=Постачальник OAuth2 +auths.tip.dropbox=Додайте новий додаток на https://www.dropbox.com/developers/apps +auths.tip.facebook=Створіть новий додаток на https://developers.facebook.com/apps і додайте модуль "Facebook Login +auths.tip.github=Додайте OAuth додаток на https://github.com/settings/applications/new +auths.tip.gitlab=Додайте новий додаток на https://gitlab.com/profile/applications +auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (/.well-known/openid-configuration) для автоматичної настройки входу OAuth +auths.edit=Редагувати джерело автентифікації +auths.update=Оновити джерело автентифікації +auths.delete=Видалити джерело автентифікації +auths.delete_auth_title=Видалити джерело автентифікації config.server_config=Конфігурація сервера config.app_name=Назва сайту config.app_ver=Версія Gitea config.app_url=Базова URL-адреса Gitea +config.custom_conf=Шлях до файлу конфігурації +config.domain=Домен SSH сервера +config.disable_router_log=Вимкнути логування роутеру +config.run_user=Запуск від імені Користувача config.run_mode=Режим виконання config.git_version=Версія Git config.repo_root_path=Кореневий шлях репозиторія @@ -822,7 +963,14 @@ config.script_type=Тип скрипта config.ssh_config=Конфігурація SSH config.ssh_enabled=Увімкнено +config.ssh_domain=Домен сервера config.ssh_port=Порт +config.ssh_listen_port=Порт що прослуховується +config.ssh_root_path=Шлях до кореню +config.ssh_key_test_path=Шлях до тестового ключа +config.ssh_keygen_path=Шлях до генератора ключів ('ssh-keygen') +config.ssh_minimum_key_size_check=Мінімальний розмір ключа перевірки +config.ssh_minimum_key_sizes=Мінімальні розміри ключів config.db_config=Конфігурація бази даних config.db_type=Тип @@ -835,16 +983,32 @@ config.db_path=Шлях config.db_path_helper=(для "sqlite3" і "tidb") config.service_config=Конфігурація сервісу +config.register_email_confirm=Потрібно підтвердити електронну пошту для реєстрації +config.disable_register=Вимкнути самостійну реєстрацію +config.enable_openid_signup=Увімкнути самостійну реєстрацію за допомогою OpenID +config.enable_openid_signin=Увімкнути реєстрацію за допомогою OpenID +config.show_registration_button=Показувати кнопку "Реєстрація +config.mail_notify=Увімкнути сповіщення електронною поштою config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа config.enable_captcha=Увімкнути CAPTCHA +config.active_code_lives=Час актуальності кода підтвердження +config.default_keep_email_private=Приховати адресу електронної пошти за замовчуванням +config.default_allow_create_organization=Дозволити створення організацій за замовчуванням +config.default_enable_timetracking=Увімкнути відстеження часу за замовчуванням config.webhook_config=Конфігурація web-хуків +config.queue_length=Довжина черги +config.deliver_timeout=Затримка доставлення +config.skip_tls_verify=Пропустити перевірку TLS config.mailer_enabled=Увімкнено config.mailer_disable_helo=Вимкнути HELO config.mailer_name=Ім'я config.mailer_host=Хост config.mailer_user=Користувач +config.mailer_use_sendmail=Використовувати Sendmail +config.mailer_sendmail_path=Шлях до Sendmail +config.send_test_mail=Відправити тестового листа config.oauth_config=Конфігурація OAuth config.oauth_enabled=Увімкнено @@ -856,7 +1020,10 @@ config.cache_conn=Підключення до кешу config.session_config=Конфігурація сесії config.session_provider=Провайдер сесії +config.provider_config=Конфігурація постачальника config.cookie_name=Ім'я файлу cookie +config.enable_set_cookie=Увімкнути встановлення cookie +config.gc_interval_time=Інтервал запуску GC config.session_life_time=Час життя сесії config.https_only=Тільки HTTPS config.cookie_life_time=Час життя cookie-файлу @@ -867,6 +1034,9 @@ config.enable_federated_avatar=Увімкнути зовнішні аватар config.git_config=Конфігурація git config.git_disable_diff_highlight=Вимкнути підсвітку синтаксису diff +config.git_max_diff_lines=Максимум рядків на diff (на один файл) +config.git_max_diff_line_characters=Максимум символів на diff (на одну строку) +config.git_max_diff_files=Максимум diff-файлів (для показу) config.git_gc_args=Аргументи GC config.git_migrate_timeout=Тайм-аут міграції config.git_mirror_timeout=Тайм-аут оновлення дзеркала @@ -875,6 +1045,7 @@ config.git_pull_timeout=Тайм-аут операції Pull config.git_gc_timeout=Тайм-аут операції GC config.log_config=Конфігурація журналу +config.log_mode=Режим журналювання monitor.cron=Завдання cron monitor.name=Ім'я @@ -889,6 +1060,8 @@ monitor.execute_time=Час виконання notices.system_notice_list=Сповіщення системи notices.actions=Дії notices.select_all=Вибрати все +notices.deselect_all=Скасувати виділення +notices.inverse_selection=Інвертувати виділене notices.delete_selected=Видалити обране notices.delete_all=Видалити усі cповіщення notices.type=Тип @@ -899,21 +1072,26 @@ notices.op=Оп. [action] create_repo=створено репозиторій %s rename_repo=репозиторій перейменовано з %[1]s на %[3]s -commit_repo=запушено до %[3]s у %[4]s -create_issue=`відкрито проблему %s#%[2]s` +commit_repo=виконав(ла) push в %[3]s у %[4]s +create_issue=`відкрив(ла) проблему %s#%[2]s` close_issue=`закрито проблему %s#%[2]s` -reopen_issue=`повторно відкрито проблему %s#%[2]s` +reopen_issue=`повторно відкрив(ла) проблему %s#%[2]s` create_pull_request=`створено запити на злиття %s#%[2]s` +close_pull_request=`закрито запит на злиття %s#%[2]s` reopen_pull_request=`повторно відкрито запит на злиття %s#%[2]s` -comment_issue=`відкоментовано проблему %s#%[2]s` +comment_issue=`прокоментував(ла) проблему %s#%[2]s` merge_pull_request=`запит на злиття злито %s#%[2]s` transfer_repo=перенесено репозиторій %s у %s +push_tag=створив(ла) тег %[2]s в %[3]s delete_tag=видалено мітку %[2]s з %[3]s delete_branch=видалено гілку %[2]s з %[3]s +compare_commits=Порівняти %d комітів [tool] ago=%s тому +from_now=%s з цього моменту now=зараз +future=в майбутньому 1s=1 секунда 1m=1 хвилина 1h=1 година @@ -932,6 +1110,7 @@ raw_seconds=секунди raw_minutes=хвилини [dropzone] +default_message=Перетягніть файли або натисніть тут, щоб завантажити. file_too_big=Розмір файлу ({{filesize}} MB), що більше ніж максимальний розмір: ({{maxFilesize}} MB). remove_file=Видалити файл @@ -939,11 +1118,15 @@ remove_file=Видалити файл notifications=Сповіщення unread=Непрочитані read=Прочитані +no_unread=Немає непрочитаних сповіщень. +no_read=Немає прочитаних сповіщень. +pin=Прикріпити сповіщення mark_as_read=Позначити як прочитане mark_as_unread=Позначити як непрочитане mark_all_as_read=Позначити всі як прочитані [gpg] +error.not_signed_commit=Непідписаний коміт [units] diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index dadb7e000e5..c7e94726f48 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -1,11 +1,15 @@ +app_desc=一款极易搭建的自助 Git 服务 home=首页 dashboard=控制面板 explore=探索 help=帮助 sign_in=登录 +sign_in_with=登录方式 sign_out=退出 +sign_up=注册 link_account=链接帐户 +link_account_signin_or_signup=使用已有账号登录来连接到此账号,或者注册一个新账号 register=注册 website=官方网站 version=当前版本 @@ -14,10 +18,17 @@ template=模板 language=语言选项 notifications=通知 create_new=创建… +user_profile_and_more=个人信息和配置 signed_in_as=已登录用户 +enable_javascript=使用 JavaScript能使本网站更好的工作。 username=用户名 +email=电子邮件地址 password=密码 +re_type=重新输入密码 +captcha=验证码 +twofa=两步验证 +twofa_scratch=两步验证口令 passcode=验证码 repository=仓库 @@ -29,8 +40,12 @@ new_mirror=创建新的镜像 new_fork=新的仓库Fork new_org=创建新的组织 manage_org=管理我的组织 +admin_panel=管理后台 account_settings=帐户设置 settings=帐户设置 +your_profile=个人信息 +your_starred=已点赞 +your_settings=设置 all=所有 sources=自建 @@ -46,28 +61,97 @@ cancel=取消 [install] install=安装页面 +title=初始配置 +docker_helper=如果您正在使用 Docker 容器运行 Gitea,请务必先仔细阅读 官方文档 后再对本页面进行填写。 +requite_db_desc=Gitea 要求安装 MySQL、PostgreSQL、SQLite3 或 TiDB。 db_title=数据库设置 db_type=数据库类型 host=数据库主机 +user=用户名 password=数据库用户密码 db_name=数据库名称 +db_helper=MySQL 用户注意: 请使用 InnoDB 存储引擎和 "utf8_general_ci" 字符集。 +ssl_mode=SSL path=数据库文件路径 - +sqlite_helper=SQLite3 或 TiDB 数据库的文件路径。如果以服务的方式运行 Gitea, 请输入绝对路径。 +err_empty_db_path=SQLite3 或 TiDB 的数据库路径不能为空。 +err_invalid_tidb_name=TiDB 数据库名称不能包含 "." 和 "-" 字符。 +no_admin_and_disable_registration=您不能够在未创建管理员用户的情况下禁止注册。 +err_empty_admin_password=管理员密码不能为空。 + +general_title=一般设置 +app_name=站点名称 +app_name_helper=您可以在此输入您公司的名称。 repo_path=仓库根目录 +repo_path_helper=所有远程 Git 仓库将保存到此目录。 +lfs_path=LFS根目录 +lfs_path_helper=存储为Git LFS的文件将被存储在此目录。留空禁用LFS +run_user=以用户名运行 +run_user_helper=输入 Gitea 运行的操作系统用户名。请注意, 此用户必须具有对存储库根路径的访问权限。 +domain=SSH 服务域名 +domain_helper=用于 SSH 克隆的域名或主机地址。 +ssh_port=SSH 服务端口 +ssh_port_helper=SSH 服务器的端口号,为空则禁用它。 +http_port=HTTP 服务端口 +http_port_helper=Giteas web 服务器将侦听的端口号。 +app_url=Gitea 基本 URL。 +app_url_helper=用于 HTTP (S) 克隆和电子邮件通知的基本地址。 log_root_path=日志路径 +log_root_path_helper=日志文件将写入此目录。 optional_title=可选设置 +email_title=电子邮箱设置 smtp_host=SMTP 主机 +smtp_from=电子邮件发件人 +smtp_from_helper=电子邮件地址 Gitea 将使用。输入一个普通的电子邮件地址或使用 "名称" 格式。 +mailer_user=SMTP 用户名 +mailer_password=SMTP 密码 +register_confirm=需要发电子邮件确认注册 +mail_notify=启用邮件通知提醒 +server_service_title=服务器和第三方服务设置 +offline_mode=启用本地模式 +offline_mode_popup=禁用第三方 CDN 并在本地服务所有资源。 +disable_gravatar=禁用 Gravatar 头像 +disable_gravatar_popup=禁用 Gravatar 和第三方头像源。除非用户在本地上传头像, 否则将使用默认的头像。 +federated_avatar_lookup=启用 Federated 头像 federated_avatar_lookup_popup=启用 Federated Avatars 查找以使用开源的 Libravatar 服务。 +disable_registration=禁止用户自助注册 +disable_registration_popup=禁用用户自助注册。只有管理员才能创建新的用户帐户。 openid_signin=启用 OpenID 登录 +openid_signin_popup=启用通过 OpenID 登录 +openid_signup=启用 OpenID 自助注册 +openid_signup_popup=启用基于 OpenID 的用户自助注册。 +enable_captcha=启用验证码 enable_captcha_popup=要求在用户注册时输入预验证码 +require_sign_in_view=启用页面访问限制 +require_sign_in_view_popup=只有登录用户的才有页面访问权限。游客只会看到 "登录" 和注册页面 +admin_setting_desc=创建管理员帐户是可选的。第一个注册用户将自动成为管理员。 +admin_title=管理员帐号设置 +admin_name=管理员用户名 admin_password=管理员密码 confirm_password=确认密码 +admin_email=电子邮件地址 install_btn_confirm=立即安装 test_git_failed=无法识别 'git' 命令:%v +sqlite3_not_available=您所使用的发行版不支持 SQLite3,请从 %s 下载官方构建版,而不是 gobuild 版本。 +invalid_db_setting=数据库设置无效: %v +invalid_repo_path=仓库根目录设置无效:%v +run_user_not_match=运行用户名不是当前的用户名:%s -> %s save_config_failed=应用配置保存失败:%v +invalid_admin_setting=管理员帐户设置无效: %v +install_success=欢迎 !非常感谢您选择 Gitea,玩得开心。 +invalid_log_root_path=日志路径无效: %v +default_keep_email_private=默认情况下隐藏电子邮件地址 +default_keep_email_private_popup=默认情况下, 隐藏新用户帐户的电子邮件地址。 +default_allow_create_organization=默认情况下允许创建组织 +default_allow_create_organization_popup=默认情况下, 允许新用户帐户创建组织。 +default_enable_timetracking=默认情况下启用时间跟踪 +default_enable_timetracking_popup=默认情况下启用新存储库的时间跟踪。 +no_reply_address=隐藏电子邮件 +no_reply_address_helper=具有隐藏电子邮件地址的用户的域名。例如, 用户名 "joe" 将以 "joe@noreply.example.org" 的身份登录到 Git 中. 如果隐藏的电子邮件域设置为 "noreply.example.org"。 [home] +uname_holder=登录名或电子邮箱地址 password_holder=密码 switch_dashboard_context=切换控制面板用户 my_repos=我的仓库 @@ -86,31 +170,52 @@ users=用户 organizations=组织 search=搜索 code=代码 +repo_no_results=未找到匹配的仓库。 +user_no_results=未找到匹配的用户。 +org_no_results=未找到匹配的组织。 +code_no_results=未找到与搜索字词匹配的源代码。 +code_search_results=“%s” 的搜索结果是 [auth] +create_new_account=注册帐号 register_helper_msg=已经注册?立即登录! +social_register_helper_msg=已经注册?立即绑定! +disable_register_prompt=对不起,注册功能已被关闭。请联系网站管理员。 +disable_register_mail=已禁用注册的电子邮件确认。 remember_me=记住登录 forgot_password_title=忘记密码 forgot_password=忘记密码? +sign_up_now=还没帐户?马上注册。 confirmation_mail_sent_prompt=一封新的确认邮件已经被发送至 %s,请检查您的收件箱并在 %s 内完成确认注册操作。 reset_password_mail_sent_prompt=确认电子邮件已被发送到 %s。请您在 %s 内检查您的收件箱 ,完成密码重置过程。 active_your_account=激活您的帐户 +prohibit_login=禁止登录 +prohibit_login_desc=您的帐户被禁止登录,请与网站管理员联系。 +resent_limit_prompt=您请求发送激活邮件过于频繁,请等待 3 分钟后再试! has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 %s 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。 resend_mail=单击此处重新发送确认邮件 email_not_associate=您输入的邮箱地址未被关联到任何帐号! send_reset_mail=单击此处(重新)发送您的密码重置邮件 reset_password=重置密码 +invalid_code=此确认密钥无效或已过期。 reset_password_helper=单击此处重置密码 password_too_short=密码长度不能少于 %d 位! +non_local_account=非本地帐户不能通过 Gitea 的 web 界面更改密码。 verify=验证 scratch_code=验证口令 use_scratch_code=使用验证口令 twofa_scratch_used=你已经使用了你的验证口令。你将会转到两步验证设置页面以便移除你的注册设备或者重新生成新的验证口令。 +twofa_passcode_incorrect=你的验证码不正确。如果你丢失了你的设备,请使用你的验证口令。 twofa_scratch_token_incorrect=你的验证口令不正确。 +login_userpass=登录 login_openid=OpenID openid_connect_submit=连接 openid_connect_title=连接到现有的帐户 +openid_connect_desc=所选的 OpenID URI 未知。在这里关联一个新帐户。 openid_register_title=创建新帐户 +openid_register_desc=所选的 OpenID URI 未知。在这里关联一个新帐户。 +openid_signin_desc=输入您的 OpenID URI。例如: https://anne.me、bob.openid.org.cn 或 gnusocial.net/carry。 +disable_forgot_password_mail=密码重置已被禁用。请与网站管理员联系。 [mail] activate_account=请激活您的帐户 @@ -122,12 +227,14 @@ register_notify=欢迎来到 Gitea [modal] yes=确认操作 no=取消操作 +modify=更新 [form] UserName=用户名 RepoName=仓库名称 Email=邮箱地址 Password=密码 +Retype=重新输入密码 SSHTitle=SSH 密钥名称 HttpsUrl=HTTPS URL 地址 PayloadUrl=推送地址 @@ -143,6 +250,9 @@ TreeName=文件路径 Content=内容 require_error=不能为空。 +alpha_dash_error=应该只包含字母数字、破折号 ('-') 和下划线 ('_') 字符。 +alpha_dash_dot_error=' 应该只包含字母数字, 破折号 ('-'), 下划线 ('_') 和点 ('. ') 。 +git_ref_name_error=` 必须是格式良好的 git 引用名称。` size_error=长度必须为 %s。 min_size_error=长度最小为 %s 个字符。 max_size_error=长度最大为 %s 个字符。 @@ -150,24 +260,48 @@ email_error=不是一个有效的邮箱地址。 url_error=不是一个有效的 URL。 include_error=必须包含子字符串 '%s'。 unknown_error=未知错误: - +captcha_incorrect=验证码不正确。 +password_not_match=密码不匹配。 + +username_been_taken=用户名已被使用。 +repo_name_been_taken=仓库名称已被使用。 +org_name_been_taken=组织名称已被使用。 +team_name_been_taken=团队名称已被使用。 +team_no_units_error=至少选择一项仓库单元。 +email_been_used=该电子邮件地址已在使用中。 +openid_been_used=OpenID 地址 '%s' 已被使用。 +username_password_incorrect=用户名或密码不正确。 +enterred_invalid_repo_name=输入的仓库名称不正确 +enterred_invalid_owner_name=新的所有者名称无效。 +enterred_invalid_password=输入的密码不正确 user_not_exist=该用户名不存在 +last_org_owner=您不能从 "所有者" 团队中删除最后一个用户。在任何给定的团队中必须至少有一个所有者。 +cannot_add_org_to_team=组织不能被加入到团队中。 +invalid_ssh_key=无法验证您的 SSH 密钥: %s +invalid_gpg_key=无法验证您的 GPG 密钥: %s +unable_verify_ssh_key=无法验证SSH密钥,再次检查是否有误。 auth_failed=授权验证失败:%v +still_own_repo=此帐户仍拥有至少一个仓库,您需要先删除或转移它们。 +still_has_org=此帐户仍隶属于一个或多个组织,您需要退出他们。 +org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除组织操作! target_branch_not_exist=目标分支不存在。 [user] +change_avatar=修改头像 join_on=加入于 repositories=仓库列表 activity=公开活动 followers=关注者 +starred=已点赞 following=关注中 follow=关注 unfollow=取消关注 form.name_reserved='%s' 用户名被保留。 +form.name_pattern_not_allowed=用户名中不允许使用 "%s"。 [settings] profile=个人信息 @@ -176,44 +310,96 @@ security=安全 avatar=头像设置 ssh_gpg_keys=SSH / GPG 密钥 social=社交帐号绑定 +applications=访问令牌(Access Tokens) +orgs=管理组织 repos=仓库列表 delete=删除帐户 twofa=两步验证 +account_link=已绑定帐户 +organization=组织 uid=用户 ID public_profile=公开信息 +profile_desc=您的电子邮件地址将用于通知和其他操作。 +password_username_disabled=不允许非本地用户更改他们的用户名。更多详情请联系您的系统管理员。 full_name=自定义名称 website=个人网站 location=所在地区 update_profile=更新信息 update_profile_success=您的资料信息已经更新 +change_username=您的用户名已更改。 +change_username_prompt=注意:更改账户名将同时改变账户的URL continue=继续操作 cancel=取消操作 +language=界面语言 +lookup_avatar_by_mail=从电子邮箱地址查找头像 federated_avatar_lookup=Federated Avatar 查找 enable_custom_avatar=启动自定义头像 choose_new_avatar=选择新的头像 +update_avatar=更新头像 delete_current_avatar=删除当前头像 +uploaded_avatar_not_a_image=上传的文件不是一张图片。 +update_avatar_success=您的头像已更新。 +change_password=更新密码 old_password=当前密码 new_password=新的密码 +retype_new_password=重新输入新的密码 +password_incorrect=当前密码不正确! +change_password_success=您的密码已更新。从现在开始使用您的新密码登录。 +password_change_disabled=非本地帐户不能通过 Gitea 的 web 界面更改密码。 emails=邮箱地址 +manage_emails=管理邮箱地址 +manage_openid=管理 OpenID 地址 email_desc=您的主要邮箱地址将被用于通知提醒和其它操作。 primary=主要 +primary_email=设为主要邮件地址 +delete_email=移除 +email_deletion=移除电子邮件地址 +email_deletion_desc=电子邮箱地址和相关信息将会被删除。使用此电子邮箱地址发送的Git提交将会保留,继续? +email_deletion_success=您的电子邮箱地址已被移除。 +openid_deletion=移除 OpenID 地址 +openid_deletion_desc=删除此 OpenID 地址将会阻止你使用它进行登录。你确定要继续吗? +openid_deletion_success=OpenID地址已被移除。 +add_new_email=添加新的邮箱地址 +add_new_openid=添加新的 OpenID URI +add_email=增加电子邮件地址 add_openid=添加 OpenID URI +add_email_confirmation_sent=一封新的确认邮件已经被发送至 %s,请检查您的收件箱并在 %s 内完成确认注册操作。 +add_email_success=新的电子邮件地址已添加。 +add_openid_success=新的 OpenID 地址已添加。 +keep_email_private=隐藏电子邮件地址 +keep_email_private_popup=您的电子邮件地址将对其他用户隐藏。 +openid_desc=OpenID 让你可以将认证转发到外部服务。 manage_ssh_keys=管理 SSH 密钥 manage_gpg_keys=管理 GPG 密钥 add_key=增加密钥 +ssh_desc=这些 SSH 公钥已经关联到你的账号。相应的私钥拥有完全操作你的仓库的权限。 +gpg_desc=这些 GPG 公钥已经关联到你的账户。请妥善保管你的私钥因为他们将被用于认证提交。 ssh_helper=需要帮助? 请查看有关 如何生成 SSH 密钥常见 SSH 问题 寻找答案。 gpg_helper=需要帮助吗?看一看 GitHub 关于GPG 的指导。 add_new_key=增加 SSH 密钥 add_new_gpg_key=添加的 GPG 密钥 +ssh_key_been_used=此 SSH 密钥已添加到您的帐户中。 +ssh_key_name_used=使用相同名称的SSH公钥已经存在! +gpg_key_id_used=使用相同名称的GPG公钥已经存在! +gpg_no_key_email_found=此 GPG 公钥没有使用任何你的电子邮箱地址。 subkeys=子项 key_id=键ID key_name=密钥名称 key_content=密钥内容 +add_key_success=您的 SSH 密钥 '%s' 添加成功。 +add_gpg_key_success=您的 GPG 密钥 '%s' 添加成功。 +delete_key=删除 +ssh_key_deletion=删除 SSH 密钥 +gpg_key_deletion=删除 GPG 密钥 +ssh_key_deletion_desc=删除 SSH 公钥将取消对应的私钥对您的 Gitea 帐户的访问权限。继续? +gpg_key_deletion_desc=删除 GPG 公钥将无法认知使用对应私钥签名的提交,继续? +ssh_key_deletion_success=GPG 密钥已被删除。 +gpg_key_deletion_success=GPG 密钥已被删除。 add_on=增加于 valid_until=有效期至 valid_forever=永久有效 @@ -225,39 +411,87 @@ key_state_desc=7 天内使用过该密钥 token_state_desc=7 天内使用过该密钥 show_openid=在个人信息上显示 hide_openid=在个人信息上隐藏 +ssh_disabled=SSH 被禁用 manage_social=管理关联社交帐户 +social_desc=这些外部账号已经绑定到你的Gitea账号。请确认这些账号,因为这些账号可以用来登录系统。 +unbind=取消链接 +unbind_success=社会帐户已从您的帐户中解除绑定。 +manage_access_token=管理Access Tokens generate_new_token=生成新的令牌 +tokens_desc=这些令牌拥有通过 Gitea API 对您的帐户的访问权限。 +new_token_desc=使用令牌的应用拥有完全访问你的账户的权限。 token_name=令牌名称 generate_token=生成令牌 +generate_token_success=新令牌生成成功。请拷贝因为令牌将只会显示一次。 delete_token=删除令牌 +access_token_deletion=删除Access Tokens +access_token_deletion_desc=删除一个令牌将会组织通过它访问你账号的应用。是否继续? +delete_token_success=令牌已经被删除。使用该令牌的应用将不再能够访问你的账户。 +twofa_desc=两步验证可以加强你的账户安全性。 twofa_is_enrolled=你的账户已启用了两步验证。 twofa_not_enrolled=你的账号未开启两步验证。 +twofa_disable=禁用两步认证 +twofa_scratch_token_regenerate=重新生成初始令牌 +twofa_scratch_token_regenerated=你的初始令牌是 %s。请将它保存到一个安全的地方。 +twofa_enroll=启用两步验证 +twofa_disable_note=如果需要, 可以禁用双因素身份验证。 +twofa_disable_desc=关掉两步验证会使得您的账户不安全,继续执行? +regenerate_scratch_token_desc=如果您丢失了您的验证口令或已经使用它登录, 您可以在这里重置它。 twofa_disabled=两步验证已被禁用。 scan_this_image=使用您的授权应用扫描这张图片: or_enter_secret=或者输入密钥:%s +then_enter_passcode=并输入应用程序中显示的密码: +passcode_invalid=密码不正确。再试一次。 +twofa_enrolled=你的账户已经启用了两步验证。请保存初始令牌(%s)到一个安全的地方,此令牌仅当前显示一次。 +manage_account_links=管理绑定过的账号 +manage_account_links_desc=这些外部帐户已经绑定到您的 Gitea 帐户。 +account_links_not_available=当前没有与您的 Gitea 帐户绑定的外部帐户。 +remove_account_link=删除已绑定的账号 +remove_account_link_desc=删除已绑定帐户将吊销其对您的 Gitea 帐户的访问权限。继续? +remove_account_link_success=已取消绑定帐户。 orgs_none=您现在还不是任何组织的成员。 repos_none=你并不拥有任何仓库 delete_account=删除当前帐户 +delete_prompt=此操作将永久删除您的用户帐户。它 不能 被撤消。 confirm_delete_account=确认删除帐户 +delete_account_title=删除当前帐户 +delete_account_desc=确实要永久删除此用户帐户吗? [repo] owner=拥有者 repo_name=仓库名称 +repo_name_helper=好的存储库名称使用简短、深刻和独特的关键字。 visibility=可见性 +visiblity_helper=将仓库设为私有 +visiblity_helper_forced=站点管理员强制要求新仓库为私有。 +visiblity_fork_helper=(修改该值将会影响到所有派生仓库) +clone_helper=不知道如何克隆?查看帮助 。 fork_repo=派生仓库 fork_from=派生自 +fork_visiblity_helper=无法更改派生仓库的可见性。 repo_desc=仓库描述 repo_lang=仓库语言 +repo_gitignore_helper=选择 .gitignore 模板。 license=授权许可 +license_helper=选择授权许可文件。 +readme=自述 +readme_helper=选择自述文件模板。 +auto_init=初始化存储库 (添加. gitignore、许可证和自述文件) create_repo=创建仓库 default_branch=默认分支 mirror_prune=修剪 +mirror_prune_desc=删除过时的远程跟踪引用 +mirror_interval=镜像间隔 (有效的时间单位是 ' h ', 'm', 's') +mirror_interval_invalid=镜像间隔无效。 +mirror_address=从URL克隆 +mirror_address_desc=在 URL 中包含任何必需的授权凭据。 +mirror_last_synced=上次同步 watchers=关注者 stargazers=称赞者 forks=派生仓库 @@ -266,22 +500,33 @@ reactions_more=再加载 %d form.reach_limit_of_creation=你已经达到了您的 %d 仓库的限制。 form.name_reserved=仓库名称 '%s' 是被保留的。 +form.name_pattern_not_allowed=仓库名称中不允许使用模式 "%s"。 +need_auth=需要授权验证 migrate_type=迁移类型 migrate_type_helper=该仓库将是一个 镜像 migrate_repo=迁移仓库 +migrate.clone_address=从 URL 迁移/克隆 +migrate.clone_address_desc=现有仓库的 HTTP(s) 或 Git "clone" URL +migrate.clone_local_path=或服务器本地路径 migrate.permission_denied=您没有获得导入本地仓库的权限。 +migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录! migrate.failed=迁移失败:%v +migrate.lfs_mirror_unsupported=不支持镜像 LFS 对象 - 使用 'git lfs fetch --all' 和 'git lfs push --all' 替代。 mirror_from=镜像自地址 forked_from=派生自 +fork_from_self=无法派生已经拥有的仓库! copy_link=复制链接 +copy_link_success=已复制链接 +copy_link_error=请按下 ⌘-C 或 Ctrl-C 复制 copied=复制成功 unwatch=取消关注 watch=关注 unstar=取消点赞 star=点赞 fork=派生 +download_archive=下载此仓库 no_desc=暂无描述 quick_guide=快速帮助 @@ -291,6 +536,7 @@ push_exist_repo=从命令行推送已经创建的仓库 bare_message=这个家伙很懒,什么都没有推送。 code=代码 +code.desc=查看源码、文件、提交和分支。 branch=分支 tree=目录树 filter_branch_and_tag=过滤分支或标签 @@ -307,11 +553,26 @@ file_raw=原始文件 file_history=文件历史 file_view_raw=查看原始文件 file_permalink=永久链接 +file_too_large=文件过大,无法显示。 +video_not_supported_in_browser=您的浏览器不支持使用 HTML5 'video' 标签。 stored_lfs=存储到Git LFS +commit_graph=提交图 +editor.new_file=新建文件 +editor.upload_file=上传文件 +editor.edit_file=编辑文件 editor.preview_changes=预览变更 +editor.cannot_edit_non_text_files=网页不能编辑二进制文件。 +editor.edit_this_file=编辑文件 +editor.must_be_on_a_branch=您必须在某个分支上才能对此文件进行修改操作。 +editor.fork_before_edit=您必须在派生这个仓库才能对此文件进行修改操作 +editor.delete_this_file=删除文件 +editor.must_have_write_access=您必须具有写权限才能对此文件进行修改操作。 +editor.file_delete_success=文件 %s 已被删除。 editor.name_your_file=命名文件... +editor.filename_help=通过键入名称后跟斜线 ("/") 来添加目录。通过在输入框的开头键入 "退格" 来删除目录。 editor.or=或 +editor.cancel_lower=取消 editor.commit_changes=提交变更 editor.add_tmpl=添加 '%s/<文件名>' editor.add=添加 '%s' @@ -322,22 +583,38 @@ editor.commit_directly_to_this_branch=直接提交至 单击此处 查看变动的具体内容,或者 再次提交 覆盖已发生的变动。 +editor.file_already_exists=此仓库已经存在名为 '%s' 的文件。 editor.no_changes_to_show=没有可以显示的变更。 editor.fail_to_update_file=更新/创建文件 '%s' 时发生错误:%v +editor.add_subdir=添加目录 editor.unable_to_upload_files=上传文件至 '%s' 时发生错误:%v editor.upload_files_to_dir=上传文件至 '%s' +editor.cannot_commit_to_protected_branch=不可以提交到受保护的分支 '%s'。 +commits.desc=浏览代码修改历史 commits.commits=次代码提交 +commits.search=搜索提交历史 commits.find=搜索 +commits.search_all=所有分支 commits.author=作者 commits.message=备注 commits.date=提交日期 commits.older=更旧的提交 commits.newer=更新的提交 commits.signed_by=签署人: +commits.gpg_key_id=GPG 密钥 ID +ext_issues=外部工单 +ext_issues.desc=链接到外部工单跟踪系统。 +issues.desc=组织 bug 报告、任务和里程碑。 issues.new=创建工单 issues.new.labels=标签 issues.new.no_label=未选择标签 @@ -347,15 +624,19 @@ issues.new.no_milestone=未选择里程碑 issues.new.clear_milestone=取消选中里程碑 issues.new.open_milestone=开启中的里程碑 issues.new.closed_milestone=已关闭的里程碑 -issues.new.assignee=指派成员 -issues.new.clear_assignee=取消指派成员 -issues.new.no_assignee=未指派成员 +issues.new.assignees=指派成员 +issues.new.clear_assignees=取消指派成员 +issues.new.no_assignees=未指派成员 issues.no_ref=分支/标记未指定 issues.create=创建工单 issues.new_label=创建标签 +issues.new_label_placeholder=标签名称 +issues.new_label_desc_placeholder=描述 issues.create_label=创建标签 issues.label_templates.title=加载预定义的标签模板 +issues.label_templates.info=还没有任何标签。您可以使用'创建标签'按钮或者加载预定义的标签集创建标签 issues.label_templates.helper=选择标签模板 +issues.label_templates.use=使用标签集 issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v issues.add_label_at=添加了标签
%s
%s issues.remove_label_at=删除了标签
%s
%s @@ -371,8 +652,11 @@ issues.delete_branch_at=`于 %[2]s 删除了分支 %[1]s` issues.open_tab=%d 个开启中 issues.close_tab=%d 个已关闭 issues.filter_label=标签筛选 +issues.filter_label_no_select=所有标签 issues.filter_milestone=里程碑筛选 +issues.filter_milestone_no_select=所有里程碑 issues.filter_assignee=指派人筛选 +issues.filter_assginee_no_select=所有指派成员 issues.filter_type=类型筛选 issues.filter_type.all_issues=所有工单 issues.filter_type.assigned_to_you=指派给您的 @@ -403,7 +687,9 @@ issues.commented_at=`评论于 %s` issues.delete_comment_confirm=您确定要删除该条评论吗? issues.no_content=这个人很懒,什么都没留下。 issues.close_issue=关闭 +issues.close_comment_issue=评论并关闭 issues.reopen_issue=重新开启 +issues.reopen_comment_issue=评论并重新开启 issues.create_comment=评论 issues.closed_at=`于 %[2]s 关闭` issues.reopened_at=`于 %[2]s 重新开启` @@ -422,6 +708,10 @@ issues.label_count=%d 个标签 issues.label_open_issues=%d 个开启的工单 issues.label_edit=编辑 issues.label_delete=删除 +issues.label_modify=编辑标签 +issues.label_deletion=删除标签 +issues.label_deletion_desc=删除标签会将其从所有问题中删除。继续? +issues.label_deletion_success=该标签已被删除。 issues.label.filter_sort.alphabetically=按字母顺序排序 issues.label.filter_sort.reverse_alphabetically=按字母逆序排序 issues.label.filter_sort.by_size=大小 @@ -431,32 +721,70 @@ issues.attachment.open_tab=`在新的标签页中查看 '%s'` issues.attachment.download=`点击下载 '%s'` issues.subscribe=订阅 issues.unsubscribe=取消订阅 +issues.tracker=时间跟踪 issues.start_tracking_short=开始 +issues.start_tracking=开始时间跟踪 issues.start_tracking_history=`开始工作 %s` issues.tracking_already_started=`你已经开始时间跟踪这个 工单!` issues.stop_tracking=停止 issues.stop_tracking_history=`停止工作 %s` +issues.add_time=手动添加时间 +issues.add_time_short=添加时间 issues.add_time_cancel=取消 issues.add_time_history=`添加耗时 %s` issues.add_time_hours=小时 issues.add_time_minutes=分钟 +issues.add_time_sum_to_small=没有输入时间。 issues.cancel_tracking=取消 issues.cancel_tracking_history=`取消时间跟踪 %s` - +issues.time_spent_total=总用时 +issues.time_spent_from_all_authors=`总花费时间:%s` +issues.due_date=到期时间 +issues.invalid_due_date_format=到期时间的格式错误,必须是 'yyyy-mm-dd' 的形式。 +issues.error_modifying_due_date=未能修改到期时间。 +issues.error_removing_due_date=未能删除到期时间。 +issues.due_date_form=yyyy年mm月dd日 +issues.due_date_form_add=添加到期时间 +issues.due_date_form_update=更新到期时间 +issues.due_date_form_remove=删除到期时间 +issues.due_date_not_writer=你需要仓库写入权限来更新工单到期时间。 +issues.due_date_not_set=未设置到期时间。 +issues.due_date_added=到期时间 %s %s 已添加 +issues.due_date_modified=已将到期时间从 %s %s 修改为 %s +issues.due_date_remove=到期时间 %s %s 已删除 +issues.due_date_overdue=过期 + +pulls.desc=启用合并请求和代码审阅。 pulls.new=创建合并请求 +pulls.compare_changes=创建合并请求 +pulls.compare_changes_desc=选择合并的目标分支和源分支。 +pulls.compare_base=合并到 +pulls.compare_compare=拉取从 pulls.filter_branch=过滤分支 pulls.no_results=未找到结果 +pulls.nothing_to_compare=分支内容相同,无需创建合并请求。 +pulls.has_pull_request="在这些分支之间的合并请求已存在: %[2]s%#[3]d" pulls.create=创建合并请求 pulls.title_desc=请求将 %[1]d 次代码提交从 %[2]s 合并至 %[3]s pulls.merged_title_desc=于 %[4]s 将 %[1]d 次代码提交从 %[2]s合并至 %[3]s pulls.tab_conversation=对话内容 pulls.tab_commits=代码提交 +pulls.tab_files=文件变动 pulls.reopen_to_merge=请重新打开此拉请求执行合并。 pulls.merged=已合并 +pulls.has_merged=请求已合并。 +pulls.data_broken=此合并请求因为派生仓库信息缺失而中断。 +pulls.is_checking=正在进行合并冲突检测,请稍后再试。 pulls.can_auto_merge_desc=该合并请求可以进行自动合并操作。 +pulls.cannot_auto_merge_desc=该合并请求存在冲突,无法进行自动合并操作。 +pulls.cannot_auto_merge_helper=手动合并解决此冲突 +pulls.no_merge_desc=由于未启用合并选项,此合并请求无法被合并。 +pulls.no_merge_helper=在仓库设置中启用合并选项或者手工合并请求。 pulls.merge_pull_request=合并请求 pulls.rebase_merge_pull_request=变基并合并 pulls.squash_merge_pull_request=压缩提交并合并 +pulls.invalid_merge_option=你可以在此合并请求中使用合并选项。 +pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。` milestones.new=新的里程碑 milestones.open_tab=%d 开启中 @@ -465,13 +793,22 @@ milestones.closed=于 %s关闭 milestones.no_due_date=暂无截止日期 milestones.open=开启中 milestones.close=关闭 +milestones.new_subheader=里程碑组织工单,合并请求和跟踪进度。 milestones.create=创建里程碑 milestones.title=标题 milestones.desc=描述 milestones.due_date=截止日期(可选) milestones.clear=清除 +milestones.invalid_due_date_format=到期时间的格式必须是 'yyyy-mm-dd' 的形式。 +milestones.create_success=里程碑 '%s' 已经创建。 milestones.edit=编辑里程碑 +milestones.edit_subheader=里程碑组织工单,合并请求和跟踪进度。 milestones.cancel=取消 +milestones.modify=更新里程碑 +milestones.edit_success=里程碑 %s 已经更新 +milestones.deletion=删除里程碑 +milestones.deletion_desc=删除该里程碑将会移除所有工单中相关的信息。是否继续? +milestones.deletion_success=里程碑已被删除。 milestones.filter_sort.closest_due_date=到期日从近到远 milestones.filter_sort.furthest_due_date=到期日从远到近 milestones.filter_sort.least_complete=完成度从低到高 @@ -479,17 +816,26 @@ milestones.filter_sort.most_complete=完成度从高到低 milestones.filter_sort.most_issues=工单从多到少 milestones.filter_sort.least_issues=工单从少到多 +ext_wiki=外部百科 +ext_wiki.desc=链接到外部 wiki。 wiki=百科 +wiki.welcome=欢迎来到百科! +wiki.welcome_desc=百科允许你撰写和与协作者分享文档 +wiki.desc=撰写和与协作者分享文档 +wiki.create_first_page=创建第一个页面 wiki.page=页面 wiki.filter_page=过滤页面 +wiki.new_page=页面 wiki.default_commit_message=关于此次修改的说明(可选)。 wiki.save_page=保存页面 wiki.last_commit_info=%s 于 %s 修改了此页面 wiki.edit_page_button=修改 wiki.new_page_button=新的页面 wiki.delete_page_button=删除页面 +wiki.delete_page_notice_1=百科页面 '%s' 删除后无法恢复,是否继续? wiki.page_already_exists=相同名称的 Wiki 页面已经存在。 +wiki.reserved_page=维基名称 '%s' 是被保留的。 wiki.pages=所有页面 wiki.last_updated=最后更新于 %s @@ -526,6 +872,9 @@ activity.closed_issue_label=已关闭 activity.new_issues_count_1=创建工单 activity.new_issues_count_n=创建工单 activity.new_issue_label=打开的 +activity.title.unresolved_conv_1=%d 未解决的会话 +activity.title.unresolved_conv_n=%d 未解决的会话 +activity.unresolved_conv_desc=这些最近更新的工单和合并请求还没有解决。 activity.unresolved_conv_label=打开 activity.title.releases_1=%d 版本发布 activity.title.releases_n=%d 版本发布 @@ -538,6 +887,9 @@ search.results=在 %s 中搜索 "%s" 的结果 settings=仓库设置 settings.desc=设置是你可以管理仓库设置的地方 +settings.options=仓库 +settings.collaboration=协作者 +settings.collaboration.admin=管理员 settings.collaboration.write=可写权限 settings.collaboration.read=可读权限 settings.collaboration.undefined=未定义 @@ -545,58 +897,168 @@ settings.hooks=管理 Web 钩子 settings.githooks=管理 Git 钩子 settings.basic_settings=基本设置 settings.mirror_settings=镜像设置 +settings.sync_mirror=同步 +settings.mirror_sync_in_progress=镜像同步正在进行中,请稍后后再试。 +settings.site=网站 settings.update_settings=更新仓库设置 settings.advanced_settings=高级设置 +settings.wiki_desc=启用仓库百科 +settings.use_internal_wiki=使用内置百科 +settings.use_external_wiki=使用外部百科 settings.external_wiki_url=外部 Wiki 链接 +settings.external_wiki_url_error=外部百科链接无效 +settings.external_wiki_url_desc=当点击工单标签时,访问者将被重定向到外部工单系统的URL。 +settings.issues_desc=启用工单系统 +settings.use_internal_issue_tracker=使用内置的轻量级工单管理系统 +settings.use_external_issue_tracker=使用外部的工单管理系统 settings.external_tracker_url=外部工单系统 URL +settings.external_tracker_url_error=外部百科链接无效 +settings.external_tracker_url_desc=当点击工单标签时,访问者将被重定向到外部工单系统的URL。 settings.tracker_url_format=外部工单管理系统的 URL 格式 +settings.tracker_issue_style=外部工单管理系统的编号格式 settings.tracker_issue_style.numeric=纯数字形式 settings.tracker_issue_style.alphanumeric=英文字母数字组合形式 +settings.tracker_url_format_desc=使用占位符 {user}, {repo}{index} 作为用户名、仓库名和工单索引。 +settings.enable_timetracker=启用时间跟踪 +settings.allow_only_contributors_to_track_time=仅允许成员跟踪时间 +settings.pulls_desc=启用合并请求 +settings.pulls.ignore_whitespace=忽略空白冲突 +settings.pulls.allow_merge_commits=允许合并 +settings.pulls.allow_rebase_merge=启用变基合并提交 +settings.pulls.allow_squash_commits=启用Squash合并提交 +settings.admin_settings=管理员设置 +settings.admin_enable_health_check=启用仓库健康检查 (git fsck) settings.danger_zone=危险操作区 settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库! +settings.convert=转换为普通仓库 +settings.convert_desc=您可以将该镜像仓库转换为普通仓库,但此操作不可恢复。 +settings.convert_notices_1=该操作会将镜像仓库转换为普通仓库,但该操作不可恢复。 +settings.convert_confirm=转换仓库 +settings.convert_succeed=此镜像仓库已经转换为普通仓库。 settings.transfer=转移仓库所有权 +settings.transfer_desc=您可以将仓库转移至您拥有管理员权限的帐户或组织。 +settings.transfer_notices_1=-如果将其传输给单个用户, 您将失去对存储库的访问权限。 +settings.transfer_notices_2=-如果将其转移到您 (共同) 拥有的组织,您可以继续访问该仓库。 +settings.transfer_form_title=输入仓库名称以做确认: +settings.wiki_delete=删除百科数据 +settings.wiki_delete_desc=删除仓库百科数据是永久性的,无法撤消。 +settings.wiki_delete_notices_1=- 这将永久删除和禁用 %s 的百科。 +settings.confirm_wiki_delete=删除百科数据 +settings.wiki_deletion_success=仓库百科数据删除成功! settings.delete=删除本仓库 +settings.delete_desc=删除仓库是永久性的, 无法撤消。 settings.delete_notices_1=- 此操作 不可以 被回滚。 +settings.delete_notices_2=- 此操作将永久删除仓库 %s,包括 Git 数据、 工单、评论、百科和协作者的操作权限。 +settings.delete_notices_fork_1=- 在此仓库删除后,它的派生仓库将变成独立仓库。 +settings.deletion_success=仓库已被删除。 +settings.update_settings_success=仓库设置已更新。 settings.transfer_owner=新拥有者 +settings.make_transfer=开始转移 +settings.transfer_succeed=仓库已被转移。 +settings.confirm_delete=删除本仓库 +settings.add_collaborator=增加协作者 +settings.add_collaborator_success=协作者添加成功! +settings.delete_collaborator=删除 +settings.collaborator_deletion=删除协作者 +settings.collaborator_deletion_desc=删除协作者后他将无法再对此仓库的访问。继续? +settings.remove_collaborator_success=协作者删除成功! settings.search_user_placeholder=搜索用户... +settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者! +settings.user_is_org_member=被操作的用户是组织,因此无法添加为协作者! settings.add_webhook=添加 Web 钩子 +settings.hooks_desc=当Gitea事件发生时,Web钩子自动发出HTTP POST请求。在 指南 中阅读更多内容。 +settings.webhook_deletion=删除 Web 钩子 +settings.webhook_deletion_desc=删除 web钩子 将删除其设置和历史记录。继续? +settings.webhook_deletion_success=Web 钩子删除成功! settings.webhook.test_delivery=测试推送 +settings.webhook.test_delivery_desc=用假事件测试这个 web钩子。 +settings.webhook.test_delivery_success=测试推送已经加入到队列,请耐心等待数秒再刷新推送记录。 settings.webhook.request=请求内容 settings.webhook.response=响应内容 settings.webhook.headers=头信息 +settings.webhook.payload=内容 settings.webhook.body=响应体 +settings.githooks_desc=Git 钩子是由 Git 本身提供的功能,以下为 Gitea 所支持的钩子列表。 settings.githook_edit_desc=如果钩子未启动,则会显示样例文件中的内容。如果想要删除某个钩子,则提交空白文本即可。 settings.githook_name=钩子名称 settings.githook_content=钩子文本 settings.update_githook=更新钩子设置 +settings.add_webhook_desc=Gitea 将向目标 URL 发送具有指定内容类型的 POST 请求。在 webhooks 指南 中阅读更多内容。 +settings.payload_url=目标 URL +settings.content_type=POST Content Type settings.secret=密钥文本 settings.slack_username=服务名称 settings.slack_icon_url=图标 URL settings.discord_username=用户名 settings.discord_icon_url=图标 URL settings.slack_color=颜色代码 +settings.event_desc=触发条件: +settings.event_push_only=推送事件 +settings.event_send_everything=所有事件 +settings.event_choose=自定义事件... settings.event_create=创建 +settings.event_create_desc=创建分支或标签 settings.event_pull_request=合并请求 +settings.event_pull_request_desc=开启、关闭、重新开启、编辑、指派、取消指派、更新标签、清除标签或同步合并请求 settings.event_push=推送 +settings.event_push_desc=Git 仓库推送 settings.event_repository=仓库 +settings.event_repository_desc=创建或删除仓库 +settings.active=包括事件详细信息 +settings.active_helper=添加信息描述触发事件 +settings.add_hook_success=Web 钩子添加成功! settings.update_webhook=更新 Web 钩子 +settings.update_hook_success=Web 钩子更新成功! +settings.delete_webhook=删除 Web 钩子 settings.recent_deliveries=最近推送记录 settings.hook_type=钩子类型 +settings.add_slack_hook_desc=将 Slack 集成到您的仓库中。 settings.slack_token=令牌 settings.slack_domain=域名 settings.slack_channel=频道 +settings.add_discord_hook_desc=将 Discord 集成到您的仓库中。 +settings.add_dingtalk_hook_desc=将 Dingtalk 集成到您的仓库中。 settings.deploy_keys=管理部署密钥 settings.add_deploy_key=添加部署密钥 +settings.deploy_key_desc=部署密钥具有对仓库的只读拉取权限。 +settings.is_writable=启用写权限 +settings.is_writable_info=允许此部署密钥 推送 提交到仓库。 +settings.no_deploy_keys=没有部署密钥。 settings.title=标题 settings.deploy_key_content=密钥文本 +settings.key_been_used=具有相同内容的部署密钥已在使用中。 +settings.key_name_used=使用相同名称的部署密钥已经存在! +settings.add_key_success=部署密钥 '%s' 添加成功。 +settings.deploy_key_deletion=删除部署密钥 +settings.deploy_key_deletion_desc=删除部署密钥将吊销对此存储库的访问权限。继续? +settings.deploy_key_deletion_success=部署密钥已删除。 settings.branches=分支列表 settings.protected_branch=分支保护 settings.protected_branch_can_push=允许推吗? settings.protected_branch_can_push_yes=你可以推 settings.protected_branch_can_push_no=你不能推 +settings.branch_protection=分支 '%s' 的分支保护 +settings.protect_this_branch=启用分支保护 +settings.protect_this_branch_desc=防止删除并禁用 Git 强制推送到分支。 +settings.protect_whitelist_committers=启用推送白名单 +settings.protect_whitelist_committers_desc=允许列入白名单用户或团队绕过推送限制。 +settings.protect_whitelist_users=推送白名单用户: +settings.protect_whitelist_search_users=搜索用户... +settings.protect_whitelist_teams=推送白名单团队: +settings.protect_whitelist_search_teams=搜索团队... +settings.protect_merge_whitelist_committers=启用合并白名单 +settings.protect_merge_whitelist_committers_desc=仅允许白名单用户或团队合并合并请求到此分支。 +settings.protect_merge_whitelist_users=合并白名单用户: +settings.protect_merge_whitelist_teams=合并白名单团队: settings.add_protected_branch=启用保护 settings.delete_protected_branch=禁用保护 +settings.update_protect_branch_success=分支 "%s" 的分支保护已更新。 +settings.remove_protected_branch_success=分支 "%s" 的分支保护已被禁用。 +settings.protected_branch_deletion=禁用分支保护 +settings.protected_branch_deletion_desc=禁用分支保护允许具有写入权限的用户推送提交到此分支。继续? +settings.default_branch_desc=请选择一个默认的分支用于合并请求和提交: settings.choose_branch=选择一个分支... +settings.no_protected_branch=没有受保护的分支 diff.browse_source=浏览代码 diff.parent=父节点 @@ -611,6 +1073,7 @@ diff.view_file=查看文件 diff.file_suppressed=文件差异内容过多而无法显示 diff.too_many_files=部分文件因为文件数量过多而无法显示 +releases.desc=跟踪项目版本和下载。 release.releases=版本发布 release.new_release=发布新版 release.draft=草稿 @@ -619,31 +1082,58 @@ release.stable=稳定 release.edit=编辑 release.ahead=在该版本发布之后已有 %d 次代码提交到 %s 分支 release.source_code=源代码 +release.new_subheader=版本发布组织项目的版本。 +release.edit_subheader=版本发布组织项目的版本。 release.tag_name=标签名称 release.target=目标分支 +release.tag_helper=选择一个存在的标签或者创建新标签。 release.title=标题 release.content=内容 release.write=内容编辑 release.preview=效果预览 release.loading=正在加载... +release.prerelease_desc=标记为预发行 +release.prerelease_helper=标记此版本不适合生产使用。 release.cancel=取消 release.publish=发布版本 release.save_draft=保存草稿 +release.edit_release=编辑发布信息 +release.delete_release=删除发布 +release.deletion=删除发布 +release.deletion_desc=删除一个版本发布将从仓库中删除对应的Git标签。仓库内容和历史将保持不变,继续? release.deletion_success=Release已被删除。 +release.tag_name_already_exist=使用此标签名称的发布版本已经存在。 +release.tag_name_invalid=标签名称无效。 release.downloads=下载附件 +branch.name=分支名称 branch.search=搜索分支 +branch.already_exists=名为 '%s' 的分支已存在。 branch.delete_head=刪除 +branch.delete=删除分支 '%s' branch.delete_html=删除分支 +branch.delete_desc=删除分支是永久的。此操作 无法 撤销,继续? +branch.deletion_success=分支 '%s' 已被删除。 +branch.deletion_failed=删除分支 '%s' 失败。 +branch.delete_branch_has_new_commits=因为合并之后有新的提交,分支 %s 无法被删除。 branch.create_branch=创建分支 %s branch.create_from=从 '%s' +branch.create_success=分支 '%s' 已创建。 branch.branch_already_exists=此仓库已存在名为 '%s' 的分支。 +branch.branch_name_conflict=分支 '%s' 与已存在的分支 '%s' 名称冲突。 +branch.tag_collision=分支 '%s' 不能被创建因为同名的标签已经存在。 branch.deleted_by=删除人:%s +branch.restore_success=分支 '%s' 已恢复。 +branch.restore_failed=未能还原分支%s。 +branch.protected_deletion_failed=分支 '%s' 已被保护,不可删除。 +topic.manage_topics=管理主题 +topic.done=已完成 [org] org_name_holder=组织名称 org_full_name_holder=组织全名 +org_name_helper=组织名字应该简单明了。 create_org=创建组织 repo_updated=最后更新于 people=组织成员 @@ -655,20 +1145,37 @@ create_team=创建团队 org_desc=组织描述 team_name=团队名称 team_desc=团队描述 +team_name_helper=团队名字应该简单明了。 +team_desc_helper=描述团队的目的或作用。 +team_permission_desc=权限 +team_unit_desc=允许访问仓库单元 +form.name_reserved=组织名称 '%s' 是被保留的。 +form.name_pattern_not_allowed=仓库名称中不允许使用 "%s"。 +form.create_org_not_allowed=此账号禁止创建组织 settings=组织设置 +settings.options=组织 settings.full_name=组织全名 settings.website=官方网站 settings.location=所在地区 settings.update_settings=更新组织设置 settings.update_setting_success=组织设置已更新。 +settings.change_orgname_prompt=注意:修改组织名称将会同时修改对应的URL。 +settings.update_avatar_success=组织头像已经更新。 settings.delete=删除组织 settings.delete_account=删除当前组织 +settings.delete_prompt=删除操作会永久清除该组织的信息,并且 不可恢复! settings.confirm_delete_account=确认删除组织 +settings.delete_org_title=删除组织 +settings.delete_org_desc=此组织将会被永久删除,确认继续吗? settings.hooks_desc=在此处添加的 Web 钩子将会应用到该组织下的 所有仓库。 members.membership_visibility=成员可见性: +members.public=可见 +members.public_helper=隐藏 +members.private=隐藏 +members.private_helper=显示 members.member_role=成员角色: members.owner=管理员 members.member=普通成员 @@ -680,13 +1187,24 @@ members.invite_now=立即邀请 teams.join=加入团队 teams.leave=离开团队 teams.read_access=读取权限 +teams.read_access_helper=成员可以查看和克隆团队仓库。 teams.write_access=写入权限 +teams.write_access_helper=成员可以查看和推送提交到团队仓库。 +teams.admin_access=管理员权限 +teams.admin_access_helper=成员可以拉取和推送到团队仓库同时可以添加协作者。 teams.no_desc=该团队暂无描述 teams.settings=团队设置 +teams.owners_permission_desc=管理员团队对 所有仓库 具有操作权限,且对组织具有 管理员权限。 teams.members=团队成员 teams.update_settings=更新团队设置 +teams.delete_team=删除团队 teams.add_team_member=添加团队成员 +teams.delete_team_title=删除团队 +teams.delete_team_desc=删除一个团队将删除团队成员的访问权限,继续? teams.delete_team_success=该团队已被删除。 +teams.read_permission_desc=该团队拥有对所属仓库的 读取 权限,团队成员可以进行查看和克隆等只读操作。 +teams.write_permission_desc=该团队拥有对所属仓库的 读取写入 的权限。 +teams.admin_permission_desc=该团队拥有一定的 管理 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。 teams.repositories=团队仓库 teams.search_repo_placeholder=搜索仓库... teams.add_team_repository=添加团队仓库 @@ -695,8 +1213,10 @@ teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先 [admin] dashboard=控制面板 +users=帐户管理 organizations=组织管理 repositories=仓库管理 +authentication=认证源 config=应用配置 notices=系统提示 monitor=应用监控面板 @@ -704,6 +1224,10 @@ first_page=首页 last_page=末页 total=总计:%d +dashboard.statistic=摘要 +dashboard.operations=维护操作 +dashboard.system_status=系统状态 +dashboard.statistic_info=Gitea 数据库统计:%d 位用户,%d 个组织,%d 个公钥,%d 个仓库,%d 个仓库关注,%d 个赞,%d 次行为,%d 条权限记录,%d 张工单,%d 次评论,%d 个社交帐号,%d 个用户关注,%d 个镜像,%d 个版本发布,%d 个登录源,%d 个 Web 钩子,%d 个里程碑,%d 个标签,%d 个钩子任务,%d 个团队,%d 个更新任务,%d 个附件。 dashboard.operation_name=操作名称 dashboard.operation_switch=开关 dashboard.operation_run=执行 @@ -711,16 +1235,30 @@ dashboard.clean_unbind_oauth=清理未绑定的 OAuth 连接 dashboard.clean_unbind_oauth_success=所有未绑定的 OAuth 连接已被删除。 dashboard.delete_inactivate_accounts=删除所有未激活帐户 dashboard.delete_inactivate_accounts_success=所有未激活帐号清除成功! +dashboard.delete_repo_archives=删除所有仓库存档 +dashboard.delete_repo_archives_success=所有仓库存档清除成功! +dashboard.delete_missing_repos=删除所有丢失 Git 文件的仓库 +dashboard.delete_missing_repos_success=所有丢失对应 Git 文件的仓库已被删除。 +dashboard.git_gc_repos=对仓库进行垃圾回收 +dashboard.git_gc_repos_success=所有仓库已完成执行垃圾回收。 +dashboard.resync_all_sshkeys=重新生成 '.ssh/authorized_keys' 文件。(仅对非内置SSH服务有效) +dashboard.resync_all_sshkeys_success=所有由 Gitea 控制的公钥都被重写了。 +dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 post-receive 钩子 +dashboard.resync_all_hooks_success=所有 pre-receive, update 和 post-receive 钩子已经被重写了。 dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录 dashboard.reinit_missing_repos_success=所有丢失的 Git 仓库存在的记录已经被重新初始化。 dashboard.sync_external_users=同步外部用户数据 +dashboard.sync_external_users_started=外部用户同步已开始 dashboard.git_fsck=在所有仓库中运行监控检查 +dashboard.git_fsck_started=仓库监控检查已经开始 dashboard.server_uptime=服务运行时间 dashboard.current_goroutine=当前 Goroutines 数量 dashboard.current_memory_usage=当前内存使用量 dashboard.total_memory_allocated=所有被分配的内存 dashboard.memory_obtained=内存占用量 dashboard.pointer_lookup_times=指针查找次数 +dashboard.memory_allocate_times=内存分配次数 +dashboard.memory_free_times=内存释放次数 dashboard.current_heap_usage=当前 Heap 内存使用量 dashboard.heap_memory_obtained=Heap 内存占用量 dashboard.heap_memory_idle=Heap 内存空闲量 @@ -743,18 +1281,43 @@ dashboard.total_gc_pause=GC 暂停时间总量 dashboard.last_gc_pause=上次 GC 暂停时间 dashboard.gc_times=GC 执行次数 +users.user_manage_panel=用户帐户管理 +users.new_account=创建新帐户 +users.name=用户名 users.activated=已激活 users.admin=管理员 users.repos=仓库数 users.created=创建时间 +users.last_login=上次登录 +users.never_login=从未登录 +users.send_register_notify=发送注册通知 +users.new_success=帐户 '%s' 已被创建。 users.edit=修改 users.auth_source=认证源 users.local=本地 +users.auth_login_name=认证登录名称 +users.password_helper=保持密码为空将不更改密码。 +users.update_profile_success=该帐户已被更新。 +users.edit_account=编辑帐号 +users.max_repo_creation=最大仓库数 +users.max_repo_creation_desc=(设置为 -1 表示使用全局默认值) +users.is_activated=该用户已被激活 +users.prohibit_login=禁用登录 +users.is_admin=是管理员 +users.allow_git_hook=允许创建 Git 钩子 +users.allow_import_local=允许导入本地仓库 +users.allow_create_organization=允许创建组织 +users.update_profile=更新帐户 +users.delete_account=删除帐户 +users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。 +users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。 +users.deletion_success=用户帐户已被删除。 orgs.org_manage_panel=组织管理 orgs.name=名称 orgs.teams=团队 orgs.members=成员 +orgs.new_orga=创建新的组织 repos.repo_manage_panel=仓库管理 repos.owner=所有者 @@ -765,9 +1328,12 @@ repos.stars=点赞数 repos.issues=工单数 repos.size=从小到大 +auths.auth_manage_panel=认证源管理 +auths.new=添加认证源 auths.name=名称 auths.type=类型 auths.enabled=启用 +auths.syncenabled=启用用户同步 auths.updated=最后更新时间 auths.auth_type=认证类型 auths.auth_name=认证名称 @@ -777,8 +1343,17 @@ auths.host=主机 auths.port=端口 auths.bind_dn=绑定 DN auths.bind_password=绑定密码 +auths.bind_password_helper=警告:密码将会被明文存储。如果可能请使用只读账号。 auths.user_base=用户搜索基准 auths.user_dn=用户 DN +auths.attribute_username=用户名属性 +auths.attribute_username_placeholder=置空将使用Gitea的用户名。 +auths.attribute_name=名字属性 +auths.attribute_surname=姓氏属性 +auths.attribute_mail=电子邮箱属性 +auths.attributes_in_bind=从 Bind DN 中拉取属性信息 +auths.use_paged_search=使用分页搜索 +auths.search_page_size=分页大小 auths.filter=用户过滤规则 auths.admin_filter=管理员过滤规则 auths.ms_ad_sa=MS AD 搜索属性 @@ -786,6 +1361,7 @@ auths.smtp_auth=SMTP 认证类型 auths.smtphost=SMTP 主机地址 auths.smtpport=SMTP 主机端口 auths.allowed_domains=域名白名单 +auths.allowed_domains_helper=置空将允许所有域名,每个域名用逗号分隔。 auths.enable_tls=启用 TLS 加密 auths.skip_tls_verify=忽略 TLS 验证 auths.pam_service_name=PAM 服务名称 @@ -793,6 +1369,7 @@ auths.oauth2_provider=OAuth2 提供程序 auths.oauth2_clientID=客户端 ID (键) auths.oauth2_clientSecret=客户端密钥 auths.openIdConnectAutoDiscoveryURL=OpenID 连接自动发现 URL +auths.oauth2_use_custom_url=使用自定义的 URL 而不是默认的 URL auths.oauth2_tokenURL=令牌 URL auths.oauth2_authURL=授权 URL auths.oauth2_profileURL=Profile URL @@ -802,27 +1379,48 @@ auths.tips=帮助提示 auths.tips.oauth2.general=OAuth2 认证 auths.tips.oauth2.general.tip=当注册一个新的 OAuth2 认证,回调/重定向 URL 应该是: /user/oauth2//callback auths.tip.oauth2_provider=OAuth2 提供程序 +auths.tip.bitbucket=在 https://bitbucket.org/account/user//oauth-consumers/new 注册新的 OAuth 消费者同时添加权限"帐户"-"读 auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序 auths.tip.facebook=在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录 auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序 auths.tip.gitlab=在 https://gitlab.com/profile/applications 上注册新应用程序 +auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据 auths.tip.openid_connect=使用 OpenID 连接发现 URL (/.well-known/openid-configuration) 来指定终点 +auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 +auths.edit=修改认证源 +auths.activated=该认证源已经启用 auths.new_success=已添加身份验证 '%s'。 +auths.update_success=认证源已经更新。 +auths.update=更新认证源 +auths.delete=删除认证源 auths.delete_auth_title=删除身份验证源 +auths.delete_auth_desc=删除一个认证源将阻止使用它进行登录。确认? +auths.still_in_used=认证源仍在使用。请先解除或者删除使用此认证源的用户。 +auths.deletion_success=认证源已经更新。 +auths.login_source_exist=认证源 '%s' 已经存在。 config.server_config=服务器配置 +config.app_name=站点名称 +config.app_ver=Gitea版本 +config.app_url=Gitea 基本 URL config.custom_conf=配置文件路径 +config.domain=SSH 服务域名 +config.offline_mode=离线模式 config.disable_router_log=关闭路由日志 +config.run_user=以用户名运行 config.run_mode=运行模式 config.git_version=Git 版本 config.repo_root_path=仓库根目录 config.lfs_root_path=LFS根目录 config.static_file_root_path=静态文件根目录 +config.log_file_root_path=日志路径 config.script_type=脚本类型 config.reverse_auth_user=反向代理认证 config.ssh_config=SSH 配置 config.ssh_enabled=启用 +config.ssh_start_builtin_server=使用内置 SSH 服务器 +config.ssh_domain=SSH 服务域名 config.ssh_port=端口 config.ssh_listen_port=监听端口 config.ssh_root_path=根目录 @@ -835,21 +1433,37 @@ config.db_config=数据库配置 config.db_type=类型 config.db_host=主机 config.db_name=数据库名称 +config.db_user=用户名 +config.db_ssl_mode=SSL config.db_ssl_mode_helper=(仅限 "postgres" 使用) config.db_path=数据库路径 config.db_path_helper=(用于 "sqlite3" 和 "tidb") config.service_config=服务配置 +config.register_email_confirm=需要电子邮件确认注册 +config.disable_register=禁止用户注册 +config.enable_openid_signup=启用 OpenID 自注册 +config.enable_openid_signin=启用 OpenID 登录 config.show_registration_button=显示注册按钮 +config.require_sign_in_view=启用登录访问限制 +config.mail_notify=启用邮件通知 config.disable_key_size_check=禁用密钥最小长度检查 +config.enable_captcha=启用登录验证码 config.active_code_lives=激活用户链接有效期 config.reset_password_code_lives=重置密码验证码到期时间 +config.default_keep_email_private=默认情况下隐藏电子邮件地址 +config.default_allow_create_organization=默认情况下允许创建组织 +config.enable_timetracking=启用时间跟踪 +config.default_enable_timetracking=默认情况下启用时间跟踪 +config.default_allow_only_contributors_to_track_time=仅允许成员跟踪时间 +config.no_reply_address=隐藏电子邮件域 config.webhook_config=Web 钩子配置 config.queue_length=队列长度 config.deliver_timeout=推送超时 config.skip_tls_verify=跳过 TLS 验证 +config.mailer_config=邮件配置 config.mailer_enabled=启用服务 config.mailer_disable_helo=禁用 HELO 操作 config.mailer_name=任务名称 @@ -857,6 +1471,10 @@ config.mailer_host=邮件主机地址 config.mailer_user=发送者帐号 config.mailer_use_sendmail=使用 Sendmail config.mailer_sendmail_path=Sendmail 路径 +config.mailer_sendmail_args=Sendmail 的额外参数 +config.send_test_mail=发送测试邮件 +config.test_mail_failed=发送测试邮件至 '%s' 时失败:%v +config.test_mail_sent=测试邮件已经发送至 '%s'。 config.oauth_config=OAuth 配置 config.oauth_enabled=启用 @@ -876,6 +1494,7 @@ config.session_life_time=Session 生命周期 config.https_only=仅限 HTTPS config.cookie_life_time=Cookie 生命周期 +config.picture_config=图片和头像配置 config.picture_service=图片服务 config.disable_gravatar=禁用 Gravatar 头像 config.enable_federated_avatar=启用 Federated Avatars @@ -900,6 +1519,7 @@ monitor.name=任务名称 monitor.schedule=任务安排 monitor.next=下次执行时间 monitor.previous=上次执行时间 +monitor.execute_times=执行时间 monitor.process=运行中进程 monitor.desc=进程描述 monitor.start=开始时间 @@ -960,6 +1580,8 @@ raw_seconds=秒 raw_minutes=分钟 [dropzone] +default_message=拖动文件或者点击此处上传。 +invalid_input_type=您不能上传该类型的文件 file_too_big=文件体积({{filesize}} MB)超过了最大允许体积({{maxFilesize}} MB) remove_file=移除文件 @@ -968,6 +1590,7 @@ notifications=通知 unread=未读消息 read=已读消息 no_unread=没有未读通知。 +no_read=没有未读通知。 pin=Pin 通知 mark_as_read=标记为已读 mark_as_unread=标记为未读 @@ -976,8 +1599,12 @@ mark_all_as_read=全部标记为已读 [gpg] error.extract_sign=无法提取签名 error.generate_hash=无法生成提交的哈希 +error.no_committer_account=没有帐户链接到提交者的电子邮件 error.no_gpg_keys_found=找不到此签名对应的密钥 error.not_signed_commit=未签名的提交 +error.failed_retrieval_gpg_keys=找不到任何与该提交者账号相关的密钥 [units] +error.no_unit_allowed_repo=您没有被允许访问此仓库的任何单元。 +error.unit_not_allowed=您没有权限访问此仓库单元 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index fe2d1df76ee..9d1dd90e298 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -329,9 +329,6 @@ issues.new.no_milestone=未選擇里程碑 issues.new.clear_milestone=清除已選取里程碑 issues.new.open_milestone=開啟中的里程碑 issues.new.closed_milestone=已關閉的里程碑 -issues.new.assignee=指派成員 -issues.new.clear_assignee=取消指派成員 -issues.new.no_assignee=未指派成員 issues.create=建立問題 issues.new_label=建立標籤 issues.create_label=建立標籤 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index ce389b6907b..9487a7f9ee5 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -339,9 +339,6 @@ issues.new.no_milestone=未選擇里程碑 issues.new.clear_milestone=清除已選取里程碑 issues.new.open_milestone=開啟中的里程碑 issues.new.closed_milestone=已關閉的里程碑 -issues.new.assignee=指派成員 -issues.new.clear_assignee=取消指派成員 -issues.new.no_assignee=未指派成員 issues.no_ref=未指定分支或標籤 issues.create=建立問題 issues.new_label=建立標籤 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000000..0269b9aced3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,665 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true, + "optional": true + }, + "aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "dev": true, + "optional": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true, + "optional": true + }, + "clean-css": { + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", + "dev": true, + "requires": { + "commander": "2.8.1", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "optional": true + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "optional": true, + "requires": { + "prr": "1.0.1" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true, + "optional": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true, + "optional": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true, + "optional": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "optional": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true, + "optional": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true, + "optional": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true, + "optional": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true, + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true, + "optional": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "less": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/less/-/less-3.0.4.tgz", + "integrity": "sha512-q3SyEnPKbk9zh4l36PGeW2fgynKu+FpbhiUNx/yaiBUQ3V0CbACCgb9FzYWcRgI2DJlP6eI4jc8XPrCTi55YcQ==", + "dev": true, + "requires": { + "errno": "0.1.7", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.6.0", + "mkdirp": "0.5.1", + "promise": "7.3.1", + "request": "2.85.0", + "source-map": "0.6.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "optional": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "optional": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "optional": true, + "requires": { + "hoek": "4.2.1" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "optional": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "optional": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "optional": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "optional": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "optional": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "optional": true + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.7.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.1.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "optional": true, + "requires": { + "hoek": "4.2.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-plugin-clean-css": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/less-plugin-clean-css/-/less-plugin-clean-css-1.5.1.tgz", + "integrity": "sha1-zFeveqM5iVflbezr5jy2DCNClwM=", + "dev": true, + "requires": { + "clean-css": "3.4.28" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true, + "optional": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true, + "optional": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "dev": true, + "optional": true, + "requires": { + "asap": "2.0.6" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true, + "optional": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "sshpk": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", + "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "dev": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true, + "optional": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true, + "optional": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json index 3410bb1f358..ae0b084cd2e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "license": "MIT", "devDependencies": { - "less": "^2.7.2", + "less": "^3.0.4", "less-plugin-clean-css": "^1.5.1" } } diff --git a/public/css/index.css b/public/css/index.css index d6c79afa5ff..607ab3f6a85 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1 +1 @@ -.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7}.tribute-container ul{background:#fff}.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc}.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px}.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px}.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff}.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain}body{font-family:Lato,"Segoe UI","Microsoft YaHei",Arial,Helvetica,sans-serif!important;background-color:#fff;overflow-y:scroll;-webkit-font-smoothing:antialiased}img{border-radius:3px}.rounded{border-radius:.28571429rem!important}code,pre{font:12px Consolas,"Liberation Mono",Menlo,Courier,monospace}code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto}code.wrap,pre.wrap{white-space:pre-wrap;-ms-word-break:break-all;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word}.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full.height{padding:0;margin:0 0 -40px 0;min-height:100%}.following.bar{z-index:900;left:0;width:100%;margin:0}.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)}.following.bar .column .menu{margin-top:0}.following.bar .top.menu a.item.brand{padding-left:0}.following.bar .brand .ui.mini.image{width:30px}.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent}.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)}.following.bar .top.menu .menu{z-index:900}.following.bar .octicon{margin-right:.75em}.following.bar .octicon.fitted{margin-right:0}.following.bar .searchbox{background-color:#f4f4f4!important}.following.bar .searchbox:focus{background-color:#e9e9e9!important}.following.bar .text .octicon{width:16px;text-align:center}@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none}}.right.stackable.menu{margin-left:auto;display:flex;display:-ms-flexbox;-ms-flex-align:inherit;align-items:inherit;-ms-flex-direction:inherit;flex-direction:inherit}.ui.left{float:left}.ui.right{float:right}.ui.button,.ui.menu .item{-moz-user-select:auto;-ms-user-select:auto;-webkit-user-select:auto;user-select:auto}.ui.container.fluid.padded{padding:0 10px 0 10px}.ui.form .ui.button{font-weight:400}.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none}.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em}.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem}.ui .text.red{color:#d95c5c!important}.ui .text.red a{color:#d95c5c!important}.ui .text.red a:hover{color:#E67777!important}.ui .text.blue{color:#428bca!important}.ui .text.blue a{color:#15c!important}.ui .text.blue a:hover{color:#428bca!important}.ui .text.black{color:#444}.ui .text.black:hover{color:#000}.ui .text.grey{color:#767676!important}.ui .text.grey a{color:#444!important}.ui .text.grey a:hover{color:#000!important}.ui .text.light.grey{color:#888!important}.ui .text.green{color:#6cc644!important}.ui .text.purple{color:#6e5494!important}.ui .text.yellow{color:#FBBD08!important}.ui .text.gold{color:#a1882b!important}.ui .text.left{text-align:left!important}.ui .text.right{text-align:right!important}.ui .text.small{font-size:.75em}.ui .text.normal{font-weight:400}.ui .text.bold{font-weight:700}.ui .text.italic{font-style:italic}.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}.ui .text.thin{font-weight:400}.ui .text.middle{vertical-align:middle}.ui .message{text-align:center}.ui .header>i+.content{padding-left:.75rem;vertical-align:middle}.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D}.ui .warning.segment{border-color:#F0C36D}.ui .info.segment{border:1px solid #c5d5dd}.ui .info.segment.top{background-color:#e6f1f6!important}.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0}.ui .info.segment.top h3:last-child{margin-top:4px}.ui .info.segment.top>:last-child{margin-bottom:0}.ui .normal.header{font-weight:400}.ui .avatar.image{border-radius:3px}.ui .form .fake{display:none!important}.ui .form .sub.field{margin-left:25px}.ui .sha.label{font-family:Consolas,Menlo,Monaco,"Lucida Console",monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px}.ui.status.buttons .octicon{margin-right:4px}.ui.inline.delete-button{padding:8px 15px;font-weight:400}.ui .background.red{background-color:#d95c5c!important}.ui .background.blue{background-color:#428bca!important}.ui .background.black{background-color:#444}.ui .background.grey{background-color:#767676!important}.ui .background.light.grey{background-color:#888!important}.ui .background.green{background-color:#6cc644!important}.ui .background.purple{background-color:#6e5494!important}.ui .background.yellow{background-color:#FBBD08!important}.ui .background.gold{background-color:#a1882b!important}.ui .branch-tag-choice{line-height:20px}.overflow.menu .items{max-height:300px;overflow-y:auto}.overflow.menu .items .item{position:relative;cursor:pointer;display:block;border:none;height:auto;border-top:none;line-height:1em;color:rgba(0,0,0,.8);padding:.71428571em 1.14285714em!important;font-size:1rem;text-transform:none;font-weight:400;box-shadow:none;-webkit-touch-callout:none}.overflow.menu .items .item.active{font-weight:700}.overflow.menu .items .item:hover{background:rgba(0,0,0,.05);color:rgba(0,0,0,.8);z-index:13}.scrolling.menu .item.selected{font-weight:700!important}footer{height:40px;background-color:#fff;border-top:1px solid #d6d6d6;clear:both;width:100%;color:#888}footer .container{padding-top:10px}footer .container .fa{width:16px;text-align:center;color:#428bca}footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px}footer .container .links>:first-child{border-left:none}footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px}.hide{display:none}.center{text-align:center}.img-1{width:2px!important;height:2px!important}.img-2{width:4px!important;height:4px!important}.img-3{width:6px!important;height:6px!important}.img-4{width:8px!important;height:8px!important}.img-5{width:10px!important;height:10px!important}.img-6{width:12px!important;height:12px!important}.img-7{width:14px!important;height:14px!important}.img-8{width:16px!important;height:16px!important}.img-9{width:18px!important;height:18px!important}.img-10{width:20px!important;height:20px!important}.img-11{width:22px!important;height:22px!important}.img-12{width:24px!important;height:24px!important}.img-13{width:26px!important;height:26px!important}.img-14{width:28px!important;height:28px!important}.img-15{width:30px!important;height:30px!important}.img-16{width:32px!important;height:32px!important}@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none}.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}}@media only screen and (max-width:767px){.not-mobile{display:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%}}.hljs{background:inherit!important;padding:0!important}.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px}.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none}.ui.menu.new-menu:hover::-webkit-scrollbar{display:block}.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)}.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)}.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible}.ui.menu.new-menu a.item:last-child{padding-right:30px!important}}[v-cloak]{display:none!important}.repos-search{padding-bottom:0!important}.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important}.markdown:not(code){overflow:hidden;font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6!important;word-wrap:break-word}.markdown:not(code).file-view{padding:2em 2em 2em!important}.markdown:not(code)>:first-child{margin-top:0!important}.markdown:not(code)>:last-child{margin-bottom:0!important}.markdown:not(code) a:not([href]){color:inherit;text-decoration:none}.markdown:not(code) .absent{color:#c00}.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown:not(code) .anchor:focus{outline:0}.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important}.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block}.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit}.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown:not(code) h1 .anchor{line-height:1}.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown:not(code) h2 .anchor{line-height:1}.markdown:not(code) h3{font-size:1.5em;line-height:1.43}.markdown:not(code) h3 .anchor{line-height:1.2}.markdown:not(code) h4{font-size:1.25em}.markdown:not(code) h4 .anchor{line-height:1.2}.markdown:not(code) h5{font-size:1em}.markdown:not(code) h5 .anchor{line-height:1.1}.markdown:not(code) h6{font-size:1em;color:#777}.markdown:not(code) h6 .anchor{line-height:1.1}.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px}.markdown:not(code) blockquote{margin-left:0}.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em}.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none}.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0}.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman}.markdown:not(code) li>p{margin-top:0}.markdown:not(code) dl{padding:0}.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px}.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown:not(code) blockquote>:first-child{margin-top:0}.markdown:not(code) blockquote>:last-child{margin-bottom:0}.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all}.markdown:not(code) table th{font-weight:700}.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important}.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc}.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8}.markdown:not(code) img{max-width:100%;box-sizing:border-box}.markdown:not(code) .emoji{max-width:none}.markdown:not(code) span.frame{display:block;overflow:hidden}.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown:not(code) span.frame span img{display:block;float:left}.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center}.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown:not(code) span.align-right span img{margin:0;text-align:right}.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown:not(code) span.float-left span{margin:13px 0 0}.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown:not(code) code,.markdown:not(code) tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown:not(code) code br,.markdown:not(code) tt br{display:none}.markdown:not(code) del code{text-decoration:inherit}.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown:not(code) .highlight{margin-bottom:16px}.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal}.markdown:not(code) pre{word-wrap:normal}.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal}.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown:not(code) input[type=checkbox]{vertical-align:middle!important}.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown:not(code) .csv-data tr{border-top:0}.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em}.home{padding-bottom:80px}.home .logo{max-width:220px}.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',sans-serif,'Microsoft YaHei'}@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}.home .hero h2{font-size:2em}}@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em}.home .hero h2{font-size:3em}}.home .hero .octicon{color:#5aa509;font-size:40px;width:50px}.home .hero.header{font-size:20px}.home p.large{font-size:16px}.home .stackable{padding-top:30px}.home a{color:#5aa509}.signup{padding-top:15px;padding-bottom:80px}.install{padding-top:45px;padding-bottom:80px}.install form label{text-align:right;width:320px!important}.install form input{width:35%!important}.install form .field{text-align:left}.install form .field .help{margin-left:335px!important}.install form .field.optional .title{margin-left:38%}.install .ui .checkbox{margin-left:40%!important}.install .ui .checkbox label{width:auto!important}.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block}.ui.attached.header{background:#f0f0f0}.ui.attached.header .right{margin-top:-5px}.ui.attached.header .right .button{padding:8px 10px;font-weight:400}#create-page-form form{margin:auto}#create-page-form form .ui.message{text-align:center}@media only screen and (min-width:768px){#create-page-form form{width:800px!important}#create-page-form form .header{padding-left:280px!important}#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}#create-page-form form .help{margin-left:265px!important}#create-page-form form .optional .title{margin-left:250px!important}#create-page-form form input,#create-page-form form textarea{width:50%!important}}@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px}#create-page-form form .inline.field>label{display:block}}.signin .oauth2 div{display:inline-block}.signin .oauth2 div p{margin:10px 5px 0 0;float:left}.signin .oauth2 a{margin-right:3px}.signin .oauth2 a:last-child{margin-right:0}.signin .oauth2 img{width:32px;height:32px}.signin .oauth2 img.openidConnect{width:auto}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto}.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center}@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important}.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important}.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important}}@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px!important}.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto}.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center}@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important}.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important}.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important}}@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block}}.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important}.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important}.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center}.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important}@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important}}.new.webhook form .help{margin-left:25px}.new.webhook .events.fields .column{padding-left:40px}.githook textarea{font-family:monospace}.repository{padding-top:15px;padding-bottom:80px}.repository .header-grid{padding-top:5px;padding-bottom:5px}.repository .header-grid .ui.compact.menu{margin-left:1rem}.repository .header-grid .ui.header{margin-top:0}.repository .header-grid .mega-octicon{width:30px;font-size:30px}.repository .header-grid .ui.huge.breadcrumb{font-weight:400;font-size:1.7rem}.repository .header-grid .fork-flag{margin-left:38px;margin-top:3px;display:block;font-size:12px;white-space:nowrap}.repository .header-grid .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px}.repository .header-grid .button{margin-top:2px;margin-bottom:2px}.repository .tabs .navbar{justify-content:initial}.repository .navbar{display:flex;justify-content:space-between}.repository .navbar .ui.label{margin-top:-2px;margin-left:7px;padding:3px 5px}.repository .owner.dropdown{min-width:40%!important}.repository #file-buttons{margin-left:auto!important;font-weight:400}.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository .metas .menu{max-height:300px;overflow-x:auto}.repository .metas .ui.list .hide{display:none!important}.repository .metas .ui.list .item{padding:0}.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px}.repository .metas .ui.list a{margin:2px 0}.repository .metas .ui.list a .text{color:#444}.repository .metas .ui.list a .text:hover{color:#000}.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px}.repository .header-wrapper .ui.tabs.divider{border-bottom:none}.repository .header-wrapper .ui.tabular .octicon{margin-right:5px}.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px}.repository .filter.menu .octicon{float:left;margin-left:-5px;margin-right:-7px}.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis}.repository .select-label .desc{padding-left:16px}.repository .ui.tabs.container{margin-top:14px;margin-bottom:0}.repository .ui.tabs.container .ui.menu{border-bottom:none}.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px}.repository #clone-panel{width:350px}.repository #clone-panel input{border-radius:0;padding:5px 10px}.repository #clone-panel .clone.button{font-size:13px;padding:0 5px}.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository #clone-panel .icon.button{padding:0 10px}.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important}.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center}.repository.file.list #repo-desc{font-size:1.2em}.repository.file.list .choose.reference .header .icon{font-size:1.4em}.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline}.repository.file.list #file-buttons{font-weight:400}.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}.repository.file.list #repo-files-table thead th:first-child{display:block;position:relative;width:325%}.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px}.repository.file.list #repo-files-table td.message .isSigned{cursor:default}.repository.file.list #repo-files-table tr:hover{background-color:#ffE}.repository.file.list #repo-files-table .jumpable-path{color:#888}.repository.file.list .non-diff-file-content .header .icon{font-size:1em}.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default}.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block}.repository.file.list .non-diff-file-content .view-raw{padding:5px}.repository.file.list .non-diff-file-content .view-raw *{max-width:100%}.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px}.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em}.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:20px}.repository.file.list .non-diff-file-content .code-view table{width:100%}.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block}.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '}.repository.file.list .non-diff-file-content .code-view .active{background:#ffd}.repository.file.list .sidebar{padding-left:0}.repository.file.list .sidebar .octicon{width:16px}.repository.file.editor .treepath{width:100%}.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px}.repository.file.editor .tabular.menu .octicon{margin-right:5px}.repository.file.editor .commit-form-wrapper{padding-left:64px}.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto}.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px Consolas,"Liberation Mono",Menlo,Courier,monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce}.repository.options #interval{width:100px!important;min-width:100px}.repository.options .danger .item{padding:20px 15px}.repository.options .danger .ui.divider{margin:0}.repository.new.issue .comment.form .comment .avatar{width:3em}.repository.new.issue .comment.form .content{margin-left:4em}.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.new.issue .comment.form .content:after{border-right-color:#fff}.repository.new.issue .comment.form .content .markdown{font-size:14px}.repository.new.issue .comment.form .metas{min-width:220px}.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto}.repository.view.issue .title{padding-bottom:0!important}.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px}.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px}.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px}.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px}.repository.view.issue .title .label{margin-right:10px}.repository.view.issue .title .edit-zone{margin-top:10px}.repository.view.issue .pull-desc code{color:#0166E6}.repository.view.issue .pull.tabular.menu{margin-bottom:10px}.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px}.repository.view.issue .pull.tab.segment{border:none;padding:0;padding-top:10px;box-shadow:none;background-color:inherit}.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px}.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1}.repository.view.issue .comment-list .comment .avatar{width:3em}.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px}.repository.view.issue .comment-list .comment .actions .item{float:left}.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px}.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px}.repository.view.issue .comment-list .comment .content{margin-left:4em}.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px}.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px}.repository.view.issue .comment-list .comment .content .markdown{font-size:14px}.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block}.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000}.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none}.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:0;padding-top:10px}.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:Consolas,monospace}.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px}.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px}.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center}.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00}.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644}.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px}.repository.view.issue .comment-list .event .octicon.octicon-comment{margin-top:4px;margin-left:-35px;font-size:24px}.repository.view.issue .comment-list .event .octicon.octicon-eye{margin-top:3px;margin-left:-35px;margin-right:0;font-size:22px}.repository.view.issue .comment-list .event .octicon.octicon-x{margin-left:-33px;font-size:25px}.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px}.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px}.repository.view.issue .ui.segment.metas{margin-top:-3px}.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px}.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%}.repository .comment.form .content .field:first-child{clear:none}.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository .comment.form .content .form:after{border-right-color:#fff}.repository .comment.form .content .tab.segment{border:none;padding:0;padding-top:10px}.repository .comment.form .content textarea{height:200px;font-family:Consolas,monospace}.repository .label.list{list-style:none;padding-top:15px}.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .label.list .item a:hover{color:#000}.repository .label.list .item a.open-issues{margin-right:30px}.repository .label.list .item .ui.label{font-size:1em}.repository .milestone.list{list-style:none;padding-top:15px}.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000}.repository .milestone.list>.item>a:hover{color:#4078c0}.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0}.repository .milestone.list>.item .ui.progress .bar{height:20px}.repository .milestone.list>.item .meta{color:#999;padding-top:5px}.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px}.repository .milestone.list>.item .meta .overdue{color:red}.repository .milestone.list>.item .operate{margin-top:-15px}.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .milestone.list>.item .operate>a:hover{color:#000}.repository .milestone.list>.item .content{padding-top:10px}.repository.new.milestone textarea{height:200px}.repository.new.milestone #deadline{width:150px}.repository.compare.pull .choose.branch .octicon{padding-right:10px}.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.compare.pull .comment.form .content:after{border-right-color:#fff}.repository .filter.dropdown .menu{margin-top:1px!important}.repository.commits .header .search input{font-weight:400;padding:5px 10px}.repository #commits-table thead th:first-of-type{padding-left:15px}.repository #commits-table thead .sha{width:140px}.repository #commits-table thead .shatd{text-align:center}.repository #commits-table td.sha .sha.label{margin:0}.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB}.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0}.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:#21BA4518}.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid #21BA4580}.repository .diff-detail-box{padding:7px 0;background:#fff;line-height:30px}.repository .diff-detail-box>div:after{clear:both;content:"";display:block}.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px}.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px}.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle}.repository .diff-detail-box span.status.modify{background-color:#f0db88}.repository .diff-detail-box span.status.add{background-color:#b4e2b4}.repository .diff-detail-box span.status.del{background-color:#e9aeae}.repository .diff-detail-box span.status.rename{background-color:#dad8ff}.repository .diff-detail-box .detail-files{background:#fff;margin:0}.repository .diff-box .header{display:flex;align-items:center}.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto}.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top}.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px}.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}.repository .diff-file-box .header{background-color:#f7f7f7}.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;vertical-align:top}.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD}.repository .diff-file-box .code-diff{font-size:12px}.repository .diff-file-box .code-diff td{padding:0;padding-left:10px;border-top:none}.repository .diff-file-box .code-diff pre{margin:0}.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px}.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid}.repository .diff-file-box.file-content{clear:right}.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}.repository .repo-search-result{padding-top:10px;padding-bottom:10px}.repository .repo-search-result .lines-num a{color:inherit}.repository.quickstart .guide .item{padding:1em}.repository.quickstart .guide .item small{font-weight:400}.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository.quickstart .guide .ui.action.small.input{width:100%}.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em}.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px}.repository.release #release-list>li{list-style:none}.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px}.repository.release #release-list>li .meta{text-align:right;position:relative}.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px}.repository.release #release-list>li .meta .commit{display:block;margin-top:10px}.repository.release #release-list>li .detail{border-left:1px solid #DDD}.repository.release #release-list>li .detail .author img{margin-bottom:-3px}.repository.release #release-list>li .detail .download{margin-top:20px}.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px}.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee}.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee}.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF}.repository.new.release .target{min-width:500px}.repository.new.release .target #tag-name{margin-top:-4px}.repository.new.release .target .at{margin-left:-5px;margin-right:5px}.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px}.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px}.repository.new.release .prerelease.field{margin-bottom:0}.repository.forks .list{margin-top:0}.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD}.repository.forks .list .item .ui.avatar{float:left;margin-right:5px}.repository.forks .list .item .link{padding-top:5px}.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px}.repository.wiki.start .ui.segment .mega-octicon{font-size:48px}.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:Consolas,monospace}.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit}.repository.wiki.new .editor-preview{background-color:#fff}.repository.wiki.view .choose.page{margin-top:-5px}.repository.wiki.view .ui.sub.header{text-transform:none}.repository.wiki.view>.markdown{padding:15px 30px}.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0}@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px}}.repository.settings.collaboration .collaborator.list{padding:0}.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em}.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD}.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px}.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px}.repository.settings.branches .protected-branches .selection.dropdown{width:300px}.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px}.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0}.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0}.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block}.repository.settings.branches .branch-protection .whitelist{margin-left:26px}.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block}.repository.settings.webhook .events .column{padding-bottom:0}.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0}.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293}.repository .ui.segment.sub-menu{padding:7px;line-height:0}.repository .ui.segment.sub-menu .list{width:100%;display:flex}.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px}.repository .ui.segment.sub-menu .list .item a{color:#000}.repository .ui.segment.sub-menu .list .item a:hover{color:#666}.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)}.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important}.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem}.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important}.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0}.repository .segment.reactions{padding:.3em 1em}.repository .segment.reactions .ui.label{padding:.4em}.repository .segment.reactions .ui.label.disabled{cursor:default}.repository .segment.reactions .ui.label>img{height:1.5em!important}.repository .segment.reactions .select-reaction{float:none}.repository .segment.reactions .select-reaction:not(.active) a{display:none}.repository .segment.reactions:hover .select-reaction a{display:block}.user-cards .list{padding:0}.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}.user-cards .list .item .meta{margin-top:5px}#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em}#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0}#issue-actions{display:none}.issue.list{list-style:none;padding-top:15px}.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA}.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px}.issue.list>.item .title:hover{color:#000}.issue.list>.item .comment{padding-right:10px;color:#666}.issue.list>.item .desc{padding-top:5px;color:#999}.issue.list>.item .desc .checklist{padding-left:5px}.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important}.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%}.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important}.issue.list>.item .desc a.milestone:hover{color:#000!important}.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px}.issue.list>.item .desc .overdue{color:red}.page.buttons{padding-top:15px}.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important}.ui.form .dropzone .dz-error-message{top:140px}.settings .content{margin-top:2px}.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.settings .list>.item .green{color:#21BA45!important}.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem}.settings .list>.item>.mega-octicon{display:table-cell}.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top}.settings .list>.item .info{margin-top:10px}.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0}.settings .list.key .meta{padding-top:5px;color:#666}.settings .list.email>.item:not(:first-child){min-height:60px}.settings .list.collaborator>.item{padding:0}.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0}.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0}.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px}.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto}.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px}.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px}.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px}.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px}#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important}.tab-size-1{tab-size:1!important;-moz-tab-size:1!important}.tab-size-2{tab-size:2!important;-moz-tab-size:2!important}.tab-size-3{tab-size:3!important;-moz-tab-size:3!important}.tab-size-4{tab-size:4!important;-moz-tab-size:4!important}.tab-size-5{tab-size:5!important;-moz-tab-size:5!important}.tab-size-6{tab-size:6!important;-moz-tab-size:6!important}.tab-size-7{tab-size:7!important;-moz-tab-size:7!important}.tab-size-8{tab-size:8!important;-moz-tab-size:8!important}.tab-size-9{tab-size:9!important;-moz-tab-size:9!important}.tab-size-10{tab-size:10!important;-moz-tab-size:10!important}.tab-size-11{tab-size:11!important;-moz-tab-size:11!important}.tab-size-12{tab-size:12!important;-moz-tab-size:12!important}.tab-size-13{tab-size:13!important;-moz-tab-size:13!important}.tab-size-14{tab-size:14!important;-moz-tab-size:14!important}.tab-size-15{tab-size:15!important;-moz-tab-size:15!important}.tab-size-16{tab-size:16!important;-moz-tab-size:16!important}.stats-table{display:table;width:100%}.stats-table .table-cell{display:table-cell}.stats-table .table-cell.tiny{height:.5em}tbody.commit-list{vertical-align:baseline}.commit-body{white-space:pre-wrap}@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}}#topic_edit{margin-top:5px;display:none}#repo-topic{margin-top:5px}.CodeMirror{font:14px Consolas,"Liberation Mono",Menlo,Courier,monospace}.CodeMirror.cm-s-default{border-radius:3px;padding:0!important}.CodeMirror .cm-comment{background:inherit!important}.repository.file.editor .tab[data-tab=write]{padding:0!important}.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important}.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none}.organization{padding-top:15px;padding-bottom:80px}.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px}.organization .head .ui.header .ui.right{margin-top:5px}.organization.new.org form{margin:auto}.organization.new.org form .ui.message{text-align:center}@media only screen and (min-width:768px){.organization.new.org form{width:800px!important}.organization.new.org form .header{padding-left:280px!important}.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.organization.new.org form .help{margin-left:265px!important}.organization.new.org form .optional .title{margin-left:250px!important}.organization.new.org form input,.organization.new.org form textarea{width:50%!important}}@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px}.organization.new.org form .inline.field>label{display:block}}.organization.new.org form .header{padding-left:0!important;text-align:center}.organization.options input{min-width:300px}.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px}.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0}.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px}.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px}.organization.profile #org-info .meta .item .icon{margin-right:5px}.organization.profile .ui.top.header .ui.right{margin-top:0}.organization.profile .teams .item{padding:10px 15px}.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px}.organization.invite #invite-box{margin:auto;margin-top:50px;width:500px!important}.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px}.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px}.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee}.organization.members .list .item .ui.avatar{width:48px;height:48px}.organization.members .list .item .meta{line-height:24px}.organization.teams .detail .item{padding:10px 15px}.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee}.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD}.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}.user:not(.icon){padding-top:15px;padding-bottom:80px}.user.profile .ui.card .username{display:block}.user.profile .ui.card .extra.content{padding:0}.user.profile .ui.card .extra.content ul{margin:0;padding:0}.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea}.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px}.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%}.user.profile .ui.repository.list{margin-top:25px}.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle}.user.followers .follow .ui.button{padding:8px 15px}.user.notification .octicon{float:left;font-size:2em}.user.notification .content{float:left;margin-left:7px}.user.notification table form{display:inline-block}.user.notification table button{padding:3px 3px 3px 5px}.user.notification table tr{cursor:pointer}.user.notification .octicon.green{color:#21ba45}.user.notification .octicon.red{color:#d01919}.user.notification .octicon.purple{color:#a333c8}.user.notification .octicon.blue{color:#2185d0}.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px}.user.settings .iconFloat{float:left}.dashboard{padding-top:15px;padding-bottom:80px}.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px}.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none}.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left}.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle}.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%}.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%}.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0}.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d}.dashboard .dashboard-repos{margin:0 1px}.feeds .news>.ui.grid{margin-left:auto;margin-right:auto}.feeds .news .ui.avatar{margin-top:13px}.feeds .news p{line-height:1em}.feeds .news .time-since{font-size:13px}.feeds .news .issue.title{width:80%}.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px}.feeds .news .push.news .content ul img{margin-bottom:-2px}.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px}.feeds .news .commit-id{font-family:Consolas,monospace}.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all}.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400}.feeds .list .header .plus.icon{margin-top:5px}.feeds .list ul{list-style:none;margin:0;padding-left:0}.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA}.feeds .list ul li.private{background-color:#fcf8e9}.feeds .list ul li a{padding:6px 1.2em;display:block}.feeds .list ul li a .octicon{color:#888}.feeds .list ul li a .octicon.rear{font-size:15px}.feeds .list ul li a .star-num{font-size:12px}.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px}.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px}.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px}.admin{padding-top:15px;padding-bottom:80px}.admin .table.segment{padding:0;font-size:13px}.admin .table.segment:not(.striped){padding-top:5px}.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important}.admin .table.segment th{padding-top:5px;padding-bottom:5px}.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important}.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.admin.user .email{max-width:200px}.admin dl.admin-dl-horizontal{padding:20px;margin:0}.admin dl.admin-dl-horizontal dd{margin-left:275px}.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin.config #test-mail-btn{margin-left:5px}.explore{padding-top:15px;padding-bottom:80px}.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px}.ui.repository.list .item{padding-bottom:25px}.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px}.ui.repository.list .item .ui.header .name{word-break:break-all}.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400}.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px}.ui.repository.list .item .time{font-size:12px;color:grey}.ui.repository.branches .time{font-size:12px;color:grey}.ui.user.list .item{padding-bottom:25px}.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.user.list .item .ui.avatar.image{width:40px;height:40px}.ui.user.list .item .description{margin-top:5px}.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px}.ui.user.list .item .description a{color:#333}.ui.user.list .item .description a:hover{text-decoration:underline}.ui.button.add-code-comment{font-size:14px;height:16px;padding:0;padding-top:2px;position:absolute;width:16px;display:none}.ui.button.add-code-comment:hover{font-size:16px;margin-top:-2px;margin-left:-2px;height:20px;width:20px}.focus-lines-new .ui.button.add-code-comment.add-code-comment-right,.focus-lines-old .ui.button.add-code-comment.add-code-comment-left{display:inline-block}.comment-code-cloud{padding:4px;margin:0 auto;position:relative;border:1px solid #f1f1f1;margin-top:13px;margin-right:10px;margin-bottom:5px}.comment-code-cloud:before{content:" ";width:0;height:0;border-left:13px solid transparent;border-right:13px solid transparent;border-bottom:13px solid #f1f1f1;left:20px;position:absolute;top:-13px}.comment-code-cloud .attached.tab{border:none;padding:0;margin:0}.comment-code-cloud .attached.tab.markdown{padding:1em;min-height:168px}.comment-code-cloud .right.menu.options .item{padding:.85714286em .442857em;cursor:pointer}.comment-code-cloud .ui.form textarea{border:0}.comment-code-cloud .ui.attached.tabular.menu{background:#f7f7f7;border:1px solid #d4d4d5;padding-top:5px;padding-left:5px;margin-top:0}.comment-code-cloud .footer{border-top:1px solid #f1f1f1;margin-top:10px}.comment-code-cloud .footer .markdown-info{display:inline-block;margin:5px 0;font-size:12px;color:rgba(0,0,0,.6)}.comment-code-cloud .footer .ui.right.floated{padding-top:6px}.comment-code-cloud .footer:after{clear:both;content:"";display:block} \ No newline at end of file +.tribute-container{box-shadow:0 1px 3px 1px #c7c7c7}.tribute-container ul{background:#fff}.tribute-container li{padding:8px 12px;border-bottom:1px solid #dcdcdc}.tribute-container li img{display:inline-block;vertical-align:middle;width:28px;height:28px;margin-right:5px}.tribute-container li span.fullname{font-weight:400;font-size:.8rem;margin-left:3px}.tribute-container li.highlight,.tribute-container li:hover{background:#2185D0;color:#fff}.emoji{width:1.5em;height:1.5em;display:inline-block;background-size:contain}body{font-family:Lato,"Segoe UI","Microsoft YaHei",Arial,Helvetica,sans-serif!important;background-color:#fff;overflow-y:scroll;-webkit-font-smoothing:antialiased}img{border-radius:3px}.rounded{border-radius:.28571429rem!important}code,pre{font:12px Consolas,"Liberation Mono",Menlo,Courier,monospace}code.raw,pre.raw{padding:7px 12px;margin:10px 0;background-color:#f8f8f8;border:1px solid #ddd;border-radius:3px;font-size:13px;line-height:1.5;overflow:auto}code.wrap,pre.wrap{white-space:pre-wrap;-ms-word-break:break-all;word-break:break-all;overflow-wrap:break-word;word-wrap:break-word}.dont-break-out{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-all;-ms-hyphens:auto;-moz-hyphens:auto;-webkit-hyphens:auto;hyphens:auto}.full.height{padding:0;margin:0 0 -40px 0;min-height:100%}.following.bar{z-index:900;left:0;width:100%;margin:0}.following.bar.light{background-color:#fff;border-bottom:1px solid #DDD;box-shadow:0 2px 3px rgba(0,0,0,.04)}.following.bar .column .menu{margin-top:0}.following.bar .top.menu a.item.brand{padding-left:0}.following.bar .brand .ui.mini.image{width:30px}.following.bar .top.menu .dropdown.item.active,.following.bar .top.menu .dropdown.item:hover,.following.bar .top.menu a.item:hover{background-color:transparent}.following.bar .top.menu a.item:hover{color:rgba(0,0,0,.45)}.following.bar .top.menu .menu{z-index:900}.following.bar .octicon{margin-right:.75em}.following.bar .octicon.fitted{margin-right:0}.following.bar .searchbox{background-color:#f4f4f4!important}.following.bar .searchbox:focus{background-color:#e9e9e9!important}.following.bar .text .octicon{width:16px;text-align:center}@media only screen and (max-width:767px){.following.bar #navbar:not(.shown)>:not(:first-child){display:none}}.right.stackable.menu{margin-left:auto;display:flex;display:-ms-flexbox;-ms-flex-align:inherit;align-items:inherit;-ms-flex-direction:inherit;flex-direction:inherit}.ui.left{float:left}.ui.right{float:right}.ui.button,.ui.menu .item{-moz-user-select:auto;-ms-user-select:auto;-webkit-user-select:auto;user-select:auto}.ui.container.fluid.padded{padding:0 10px 0 10px}.ui.form .ui.button{font-weight:400}.ui.floating.label{z-index:10}.ui.menu,.ui.segment,.ui.vertical.menu{box-shadow:none}.ui .menu:not(.vertical) .item>.button.compact{padding:.58928571em 1.125em}.ui .menu:not(.vertical) .item>.button.small{font-size:.92857143rem}.ui.dropdown .menu>.item>.floating.label{z-index:11}.ui.dropdown .menu .menu>.item>.floating.label{z-index:21}.ui .text.red{color:#d95c5c!important}.ui .text.red a{color:#d95c5c!important}.ui .text.red a:hover{color:#E67777!important}.ui .text.blue{color:#428bca!important}.ui .text.blue a{color:#15c!important}.ui .text.blue a:hover{color:#428bca!important}.ui .text.black{color:#444}.ui .text.black:hover{color:#000}.ui .text.grey{color:#767676!important}.ui .text.grey a{color:#444!important}.ui .text.grey a:hover{color:#000!important}.ui .text.light.grey{color:#888!important}.ui .text.green{color:#6cc644!important}.ui .text.purple{color:#6e5494!important}.ui .text.yellow{color:#FBBD08!important}.ui .text.gold{color:#a1882b!important}.ui .text.left{text-align:left!important}.ui .text.right{text-align:right!important}.ui .text.small{font-size:.75em}.ui .text.normal{font-weight:400}.ui .text.bold{font-weight:700}.ui .text.italic{font-style:italic}.ui .text.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}.ui .text.thin{font-weight:400}.ui .text.middle{vertical-align:middle}.ui .message{text-align:center}.ui .header>i+.content{padding-left:.75rem;vertical-align:middle}.ui .warning.header{background-color:#F9EDBE!important;border-color:#F0C36D}.ui .warning.segment{border-color:#F0C36D}.ui .info.segment{border:1px solid #c5d5dd}.ui .info.segment.top{background-color:#e6f1f6!important}.ui .info.segment.top h3,.ui .info.segment.top h4{margin-top:0}.ui .info.segment.top h3:last-child{margin-top:4px}.ui .info.segment.top>:last-child{margin-bottom:0}.ui .normal.header{font-weight:400}.ui .avatar.image{border-radius:3px}.ui .form .fake{display:none!important}.ui .form .sub.field{margin-left:25px}.ui .sha.label{font-family:Consolas,Menlo,Monaco,"Lucida Console",monospace;font-size:13px;padding:6px 10px 4px 10px;font-weight:400;margin:0 6px}.ui.status.buttons .octicon{margin-right:4px}.ui.inline.delete-button{padding:8px 15px;font-weight:400}.ui .background.red{background-color:#d95c5c!important}.ui .background.blue{background-color:#428bca!important}.ui .background.black{background-color:#444}.ui .background.grey{background-color:#767676!important}.ui .background.light.grey{background-color:#888!important}.ui .background.green{background-color:#6cc644!important}.ui .background.purple{background-color:#6e5494!important}.ui .background.yellow{background-color:#FBBD08!important}.ui .background.gold{background-color:#a1882b!important}.ui .branch-tag-choice{line-height:20px}.overflow.menu .items{max-height:300px;overflow-y:auto}.overflow.menu .items .item{position:relative;cursor:pointer;display:block;border:none;height:auto;border-top:none;line-height:1em;color:rgba(0,0,0,.8);padding:.71428571em 1.14285714em!important;font-size:1rem;text-transform:none;font-weight:400;box-shadow:none;-webkit-touch-callout:none}.overflow.menu .items .item.active{font-weight:700}.overflow.menu .items .item:hover{background:rgba(0,0,0,.05);color:rgba(0,0,0,.8);z-index:13}.scrolling.menu .item.selected{font-weight:700!important}footer{height:40px;background-color:#fff;border-top:1px solid #d6d6d6;clear:both;width:100%;color:#888}footer .container{padding-top:10px}footer .container .fa{width:16px;text-align:center;color:#428bca}footer .container .links>*{border-left:1px solid #d6d6d6;padding-left:8px;margin-left:5px}footer .container .links>:first-child{border-left:none}footer .ui.language .menu{max-height:500px;overflow-y:auto;margin-bottom:7px}.hide{display:none}.center{text-align:center}.img-1{width:2px!important;height:2px!important}.img-2{width:4px!important;height:4px!important}.img-3{width:6px!important;height:6px!important}.img-4{width:8px!important;height:8px!important}.img-5{width:10px!important;height:10px!important}.img-6{width:12px!important;height:12px!important}.img-7{width:14px!important;height:14px!important}.img-8{width:16px!important;height:16px!important}.img-9{width:18px!important;height:18px!important}.img-10{width:20px!important;height:20px!important}.img-11{width:22px!important;height:22px!important}.img-12{width:24px!important;height:24px!important}.img-13{width:26px!important;height:26px!important}.img-14{width:28px!important;height:28px!important}.img-15{width:30px!important;height:30px!important}.img-16{width:32px!important;height:32px!important}@media only screen and (min-width:768px){.mobile-only,.ui.button.mobile-only{display:none}.sr-mobile-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}}@media only screen and (max-width:767px){.not-mobile{display:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}@media only screen and (max-width:991px) and (min-width:768px){.ui.container{width:95%}}.hljs{background:inherit!important;padding:0!important}.ui.menu.new-menu{justify-content:center!important;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}@media only screen and (max-width:1200px){.ui.menu.new-menu{overflow-x:auto!important;justify-content:left!important;padding-bottom:5px}.ui.menu.new-menu::-webkit-scrollbar{height:8px;display:none}.ui.menu.new-menu:hover::-webkit-scrollbar{display:block}.ui.menu.new-menu::-webkit-scrollbar-track{background:rgba(0,0,0,.01)}.ui.menu.new-menu::-webkit-scrollbar-thumb{background:rgba(0,0,0,.2)}.ui.menu.new-menu:after{position:absolute;margin-top:-15px;display:block;background-image:linear-gradient(to right,rgba(255,255,255,0),#fff 100%);content:' ';right:0;height:53px;z-index:1000;width:60px;clear:none;visibility:visible}.ui.menu.new-menu a.item:last-child{padding-right:30px!important}}[v-cloak]{display:none!important}.repos-search{padding-bottom:0!important}.repos-filter{margin-top:0!important;border-bottom-width:0!important;margin-bottom:2px!important}.markdown:not(code){overflow:hidden;font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6!important;word-wrap:break-word}.markdown:not(code).file-view{padding:2em 2em 2em!important}.markdown:not(code)>:first-child{margin-top:0!important}.markdown:not(code)>:last-child{margin-bottom:0!important}.markdown:not(code) a:not([href]){color:inherit;text-decoration:none}.markdown:not(code) .absent{color:#c00}.markdown:not(code) .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown:not(code) .anchor:focus{outline:0}.markdown:not(code) h1,.markdown:not(code) h2,.markdown:not(code) h3,.markdown:not(code) h4,.markdown:not(code) h5,.markdown:not(code) h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown:not(code) h1:first-of-type,.markdown:not(code) h2:first-of-type,.markdown:not(code) h3:first-of-type,.markdown:not(code) h4:first-of-type,.markdown:not(code) h5:first-of-type,.markdown:not(code) h6:first-of-type{margin-top:0!important}.markdown:not(code) h1 .octicon-link,.markdown:not(code) h2 .octicon-link,.markdown:not(code) h3 .octicon-link,.markdown:not(code) h4 .octicon-link,.markdown:not(code) h5 .octicon-link,.markdown:not(code) h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown:not(code) h1:hover .anchor,.markdown:not(code) h2:hover .anchor,.markdown:not(code) h3:hover .anchor,.markdown:not(code) h4:hover .anchor,.markdown:not(code) h5:hover .anchor,.markdown:not(code) h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown:not(code) h1:hover .anchor .octicon-link,.markdown:not(code) h2:hover .anchor .octicon-link,.markdown:not(code) h3:hover .anchor .octicon-link,.markdown:not(code) h4:hover .anchor .octicon-link,.markdown:not(code) h5:hover .anchor .octicon-link,.markdown:not(code) h6:hover .anchor .octicon-link{display:inline-block}.markdown:not(code) h1 code,.markdown:not(code) h1 tt,.markdown:not(code) h2 code,.markdown:not(code) h2 tt,.markdown:not(code) h3 code,.markdown:not(code) h3 tt,.markdown:not(code) h4 code,.markdown:not(code) h4 tt,.markdown:not(code) h5 code,.markdown:not(code) h5 tt,.markdown:not(code) h6 code,.markdown:not(code) h6 tt{font-size:inherit}.markdown:not(code) h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown:not(code) h1 .anchor{line-height:1}.markdown:not(code) h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown:not(code) h2 .anchor{line-height:1}.markdown:not(code) h3{font-size:1.5em;line-height:1.43}.markdown:not(code) h3 .anchor{line-height:1.2}.markdown:not(code) h4{font-size:1.25em}.markdown:not(code) h4 .anchor{line-height:1.2}.markdown:not(code) h5{font-size:1em}.markdown:not(code) h5 .anchor{line-height:1.1}.markdown:not(code) h6{font-size:1em;color:#777}.markdown:not(code) h6 .anchor{line-height:1.1}.markdown:not(code) blockquote,.markdown:not(code) dl,.markdown:not(code) ol,.markdown:not(code) p,.markdown:not(code) pre,.markdown:not(code) table,.markdown:not(code) ul{margin-top:0;margin-bottom:16px}.markdown:not(code) blockquote{margin-left:0}.markdown:not(code) hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown:not(code) ol,.markdown:not(code) ul{padding-left:2em}.markdown:not(code) ol.no-list,.markdown:not(code) ul.no-list{padding:0;list-style-type:none}.markdown:not(code) ol ol,.markdown:not(code) ol ul,.markdown:not(code) ul ol,.markdown:not(code) ul ul{margin-top:0;margin-bottom:0}.markdown:not(code) ol ol,.markdown:not(code) ul ol{list-style-type:lower-roman}.markdown:not(code) li>p{margin-top:0}.markdown:not(code) dl{padding:0}.markdown:not(code) dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown:not(code) dl dd{padding:0 16px;margin-bottom:16px}.markdown:not(code) blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown:not(code) blockquote>:first-child{margin-top:0}.markdown:not(code) blockquote>:last-child{margin-bottom:0}.markdown:not(code) table{width:auto;overflow:auto;word-break:normal;word-break:keep-all}.markdown:not(code) table th{font-weight:700}.markdown:not(code) table td,.markdown:not(code) table th{padding:6px 13px!important;border:1px solid #ddd!important}.markdown:not(code) table tr{background-color:#fff;border-top:1px solid #ccc}.markdown:not(code) table tr:nth-child(2n){background-color:#f8f8f8}.markdown:not(code) img{max-width:100%;box-sizing:border-box}.markdown:not(code) .emoji{max-width:none}.markdown:not(code) span.frame{display:block;overflow:hidden}.markdown:not(code) span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown:not(code) span.frame span img{display:block;float:left}.markdown:not(code) span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown:not(code) span.align-center{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown:not(code) span.align-center span img{margin:0 auto;text-align:center}.markdown:not(code) span.align-right{display:block;overflow:hidden;clear:both}.markdown:not(code) span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown:not(code) span.align-right span img{margin:0;text-align:right}.markdown:not(code) span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown:not(code) span.float-left span{margin:13px 0 0}.markdown:not(code) span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown:not(code) span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown:not(code) code,.markdown:not(code) tt{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown:not(code) code:after,.markdown:not(code) code:before,.markdown:not(code) tt:after,.markdown:not(code) tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown:not(code) code br,.markdown:not(code) tt br{display:none}.markdown:not(code) del code{text-decoration:inherit}.markdown:not(code) pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown:not(code) .highlight{margin-bottom:16px}.markdown:not(code) .highlight pre,.markdown:not(code) pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown:not(code) .highlight pre{margin-bottom:0;word-break:normal}.markdown:not(code) pre{word-wrap:normal}.markdown:not(code) pre code,.markdown:not(code) pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown:not(code) pre code:after,.markdown:not(code) pre code:before,.markdown:not(code) pre tt:after,.markdown:not(code) pre tt:before{content:normal}.markdown:not(code) kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:solid 1px #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown:not(code) input[type=checkbox]{vertical-align:middle!important}.markdown:not(code) .csv-data td,.markdown:not(code) .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown:not(code) .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown:not(code) .csv-data tr{border-top:0}.markdown:not(code) .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.markdown:not(code) .ui.list .list,.markdown:not(code) ol.ui.list ol,.markdown:not(code) ul.ui.list ul{padding-left:2em}.home{padding-bottom:80px}.home .logo{max-width:220px}.home .hero h1,.home .hero h2{font-family:'PT Sans Narrow',sans-serif,'Microsoft YaHei'}@media only screen and (max-width:767px){.home .hero h1{font-size:3.5em}.home .hero h2{font-size:2em}}@media only screen and (min-width:768px){.home .hero h1{font-size:5.5em}.home .hero h2{font-size:3em}}.home .hero .octicon{color:#5aa509;font-size:40px;width:50px}.home .hero.header{font-size:20px}.home p.large{font-size:16px}.home .stackable{padding-top:30px}.home a{color:#5aa509}.signup{padding-top:15px;padding-bottom:80px}.install{padding-top:45px;padding-bottom:80px}.install form label{text-align:right;width:320px!important}.install form input{width:35%!important}.install form .field{text-align:left}.install form .field .help{margin-left:335px!important}.install form .field.optional .title{margin-left:38%}.install .ui .checkbox{margin-left:40%!important}.install .ui .checkbox label{width:auto!important}.form .help{color:#999;padding-top:.6em;padding-bottom:.6em;display:inline-block}.ui.attached.header{background:#f0f0f0}.ui.attached.header .right{margin-top:-5px}.ui.attached.header .right .button{padding:8px 10px;font-weight:400}#create-page-form form{margin:auto}#create-page-form form .ui.message{text-align:center}@media only screen and (min-width:768px){#create-page-form form{width:800px!important}#create-page-form form .header{padding-left:280px!important}#create-page-form form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}#create-page-form form .help{margin-left:265px!important}#create-page-form form .optional .title{margin-left:250px!important}#create-page-form form input,#create-page-form form textarea{width:50%!important}}@media only screen and (max-width:767px){#create-page-form form .optional .title{margin-left:15px}#create-page-form form .inline.field>label{display:block}}.signin .oauth2 div{display:inline-block}.signin .oauth2 div p{margin:10px 5px 0 0;float:left}.signin .oauth2 a{margin-right:3px}.signin .oauth2 a:last-child{margin-right:0}.signin .oauth2 img{width:32px;height:32px}.signin .oauth2 img.openidConnect{width:auto}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{margin:auto}.user.activate form .ui.message,.user.forgot.password form .ui.message,.user.reset.password form .ui.message,.user.signin form .ui.message,.user.signup form .ui.message{text-align:center}@media only screen and (min-width:768px){.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:800px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:280px!important}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.user.activate form .help,.user.forgot.password form .help,.user.reset.password form .help,.user.signin form .help,.user.signup form .help{margin-left:265px!important}.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:250px!important}.user.activate form input,.user.activate form textarea,.user.forgot.password form input,.user.forgot.password form textarea,.user.reset.password form input,.user.reset.password form textarea,.user.signin form input,.user.signin form textarea,.user.signup form input,.user.signup form textarea{width:50%!important}}@media only screen and (max-width:767px){.user.activate form .optional .title,.user.forgot.password form .optional .title,.user.reset.password form .optional .title,.user.signin form .optional .title,.user.signup form .optional .title{margin-left:15px}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{display:block}}.user.activate form,.user.forgot.password form,.user.reset.password form,.user.signin form,.user.signup form{width:700px!important}.user.activate form .header,.user.forgot.password form .header,.user.reset.password form .header,.user.signin form .header,.user.signup form .header{padding-left:0!important;text-align:center}.user.activate form .inline.field>label,.user.forgot.password form .inline.field>label,.user.reset.password form .inline.field>label,.user.signin form .inline.field>label,.user.signup form .inline.field>label{width:200px!important}.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{margin:auto}.repository.new.fork form .ui.message,.repository.new.migrate form .ui.message,.repository.new.repo form .ui.message{text-align:center}@media only screen and (min-width:768px){.repository.new.fork form,.repository.new.migrate form,.repository.new.repo form{width:800px!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:280px!important}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.repository.new.fork form .help,.repository.new.migrate form .help,.repository.new.repo form .help{margin-left:265px!important}.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:250px!important}.repository.new.fork form input,.repository.new.fork form textarea,.repository.new.migrate form input,.repository.new.migrate form textarea,.repository.new.repo form input,.repository.new.repo form textarea{width:50%!important}}@media only screen and (max-width:767px){.repository.new.fork form .optional .title,.repository.new.migrate form .optional .title,.repository.new.repo form .optional .title{margin-left:15px}.repository.new.fork form .inline.field>label,.repository.new.migrate form .inline.field>label,.repository.new.repo form .inline.field>label{display:block}}.repository.new.fork form .dropdown .dropdown.icon,.repository.new.migrate form .dropdown .dropdown.icon,.repository.new.repo form .dropdown .dropdown.icon{margin-top:-7px!important}.repository.new.fork form .dropdown .text,.repository.new.migrate form .dropdown .text,.repository.new.repo form .dropdown .text{margin-right:0!important}.repository.new.fork form .dropdown .text i,.repository.new.migrate form .dropdown .text i,.repository.new.repo form .dropdown .text i{margin-right:0!important}.repository.new.fork form .header,.repository.new.migrate form .header,.repository.new.repo form .header{padding-left:0!important;text-align:center}.repository.new.repo .ui.form .selection.dropdown:not(.owner){width:50%!important}@media only screen and (min-width:768px){.repository.new.repo .ui.form #auto-init{margin-left:265px!important}}.new.webhook form .help{margin-left:25px}.new.webhook .events.fields .column{padding-left:40px}.githook textarea{font-family:monospace}.repository{padding-top:15px;padding-bottom:80px}.repository .header-grid{padding-top:5px;padding-bottom:5px}.repository .header-grid .ui.compact.menu{margin-left:1rem}.repository .header-grid .ui.header{margin-top:0}.repository .header-grid .mega-octicon{width:30px;font-size:30px}.repository .header-grid .ui.huge.breadcrumb{font-weight:400;font-size:1.7rem}.repository .header-grid .fork-flag{margin-left:38px;margin-top:3px;display:block;font-size:12px;white-space:nowrap}.repository .header-grid .octicon.octicon-repo-forked{margin-top:-1px;font-size:15px}.repository .header-grid .button{margin-top:2px;margin-bottom:2px}.repository .tabs .navbar{justify-content:initial}.repository .navbar{display:flex;justify-content:space-between}.repository .navbar .ui.label{margin-top:-2px;margin-left:7px;padding:3px 5px}.repository .owner.dropdown{min-width:40%!important}.repository #file-buttons{margin-left:auto!important;font-weight:400}.repository #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository .metas .menu{max-height:300px;overflow-x:auto}.repository .metas .ui.list .hide{display:none!important}.repository .metas .ui.list .item{padding:0}.repository .metas .ui.list .label.color{padding:0 8px;margin-right:5px}.repository .metas .ui.list a{margin:2px 0}.repository .metas .ui.list a .text{color:#444}.repository .metas .ui.list a .text:hover{color:#000}.repository .header-wrapper{background-color:#FAFAFA;margin-top:-15px;padding-top:15px}.repository .header-wrapper .ui.tabs.divider{border-bottom:none}.repository .header-wrapper .ui.tabular .octicon{margin-right:5px}.repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px}.repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px}.repository .filter.menu .text{margin-left:.9em}.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}.repository .select-label .item{max-width:250px;overflow:hidden;text-overflow:ellipsis}.repository .select-label .desc{padding-left:16px}.repository .ui.tabs.container{margin-top:14px;margin-bottom:0}.repository .ui.tabs.container .ui.menu{border-bottom:none}.repository .ui.tabs.divider{margin-top:0;margin-bottom:20px}.repository #clone-panel{width:350px}.repository #clone-panel input{border-radius:0;padding:5px 10px}.repository #clone-panel .clone.button{font-size:13px;padding:0 5px}.repository #clone-panel .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository #clone-panel .icon.button{padding:0 10px}.repository #clone-panel .dropdown .menu{right:0!important;left:auto!important}.repository.file.list .repo-description{display:flex;justify-content:space-between;align-items:center}.repository.file.list #repo-desc{font-size:1.2em}.repository.file.list .choose.reference .header .icon{font-size:1.4em}.repository.file.list .repo-path .divider,.repository.file.list .repo-path .section{display:inline}.repository.file.list #file-buttons{font-weight:400}.repository.file.list #file-buttons .ui.button{padding:8px 10px;font-weight:400}.repository.file.list #repo-files-table thead th{padding-top:8px;padding-bottom:5px;font-weight:400}.repository.file.list #repo-files-table thead th:first-child{display:block;position:relative;width:325%}.repository.file.list #repo-files-table thead .ui.avatar{margin-bottom:5px}.repository.file.list #repo-files-table tbody .octicon{margin-left:3px;margin-right:5px;color:#777}.repository.file.list #repo-files-table tbody .octicon.octicon-mail-reply{margin-right:10px}.repository.file.list #repo-files-table tbody .octicon.octicon-file-directory,.repository.file.list #repo-files-table tbody .octicon.octicon-file-submodule,.repository.file.list #repo-files-table tbody .octicon.octicon-file-symlink-directory{color:#1e70bf}.repository.file.list #repo-files-table td{padding-top:8px;padding-bottom:8px}.repository.file.list #repo-files-table td.message .isSigned{cursor:default}.repository.file.list #repo-files-table tr:hover{background-color:#ffE}.repository.file.list #repo-files-table .jumpable-path{color:#888}.repository.file.list .non-diff-file-content .header .icon{font-size:1em}.repository.file.list .non-diff-file-content .header .file-actions{margin-top:0;margin-bottom:-5px;padding-left:20px}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon{display:inline-block;padding:5px;margin-left:5px;line-height:1;color:#767676;vertical-align:middle;background:0 0;border:0;outline:0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon:hover{color:#4078c0}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon-danger:hover{color:#bd2c00}.repository.file.list .non-diff-file-content .header .file-actions .btn-octicon.disabled{color:#bbb;cursor:default}.repository.file.list .non-diff-file-content .header .file-actions #delete-file-form{display:inline-block}.repository.file.list .non-diff-file-content .view-raw{padding:5px}.repository.file.list .non-diff-file-content .view-raw *{max-width:100%}.repository.file.list .non-diff-file-content .view-raw img{padding:5px 5px 0 5px}.repository.file.list .non-diff-file-content .plain-text{padding:1em 2em 1em 2em}.repository.file.list .non-diff-file-content .code-view *{font-size:12px;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:20px}.repository.file.list .non-diff-file-content .code-view table{width:100%}.repository.file.list .non-diff-file-content .code-view .lines-num{vertical-align:top;text-align:right;color:#999;background:#f5f5f5;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.repository.file.list .non-diff-file-content .code-view .lines-num span{line-height:20px;padding:0 10px;cursor:pointer;display:block}.repository.file.list .non-diff-file-content .code-view .lines-code,.repository.file.list .non-diff-file-content .code-view .lines-num{padding:0}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs,.repository.file.list .non-diff-file-content .code-view .lines-code ol,.repository.file.list .non-diff-file-content .code-view .lines-code pre,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs,.repository.file.list .non-diff-file-content .code-view .lines-num ol,.repository.file.list .non-diff-file-content .code-view .lines-num pre{background-color:#fff;margin:0;padding:0!important}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-code ol li,.repository.file.list .non-diff-file-content .code-view .lines-code pre li,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li,.repository.file.list .non-diff-file-content .code-view .lines-num ol li,.repository.file.list .non-diff-file-content .code-view .lines-num pre li{display:block;width:100%}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-code ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-code pre li.active,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li.active,.repository.file.list .non-diff-file-content .code-view .lines-num ol li.active,.repository.file.list .non-diff-file-content .code-view .lines-num pre li.active{background:#ffd}.repository.file.list .non-diff-file-content .code-view .lines-code .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-code ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-code pre li:before,.repository.file.list .non-diff-file-content .code-view .lines-num .hljs li:before,.repository.file.list .non-diff-file-content .code-view .lines-num ol li:before,.repository.file.list .non-diff-file-content .code-view .lines-num pre li:before{content:' '}.repository.file.list .non-diff-file-content .code-view .active{background:#ffd}.repository.file.list .sidebar{padding-left:0}.repository.file.list .sidebar .octicon{width:16px}.repository.file.editor .treepath{width:100%}.repository.file.editor .treepath input{vertical-align:middle;box-shadow:rgba(0,0,0,.0745098) 0 1px 2px inset;width:inherit;padding:7px 8px;margin-right:5px}.repository.file.editor .tabular.menu .octicon{margin-right:5px}.repository.file.editor .commit-form-wrapper{padding-left:64px}.repository.file.editor .commit-form-wrapper .commit-avatar{float:left;margin-left:-64px;width:3em;height:auto}.repository.file.editor .commit-form-wrapper .commit-form{position:relative;padding:15px;margin-bottom:10px;border:1px solid #ddd;border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form:after,.repository.file.editor .commit-form-wrapper .commit-form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.file.editor .commit-form-wrapper .commit-form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.file.editor .commit-form-wrapper .commit-form:after{border-right-color:#fff}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .branch-name{display:inline-block;padding:3px 6px;font:12px Consolas,"Liberation Mono",Menlo,Courier,monospace;color:rgba(0,0,0,.65);background-color:rgba(209,227,237,.45);border-radius:3px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input{position:relative;margin-left:25px}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .new-branch-name-input input{width:240px!important;padding-left:26px!important}.repository.file.editor .commit-form-wrapper .commit-form .quick-pull-choice .octicon-git-branch{position:absolute;top:9px;left:10px;color:#b0c4ce}.repository.options #interval{width:100px!important;min-width:100px}.repository.options .danger .item{padding:20px 15px}.repository.options .danger .ui.divider{margin:0}.repository.new.issue .comment.form .comment .avatar{width:3em}.repository.new.issue .comment.form .content{margin-left:4em}.repository.new.issue .comment.form .content:after,.repository.new.issue .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.new.issue .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.new.issue .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.new.issue .comment.form .content:after{border-right-color:#fff}.repository.new.issue .comment.form .content .markdown{font-size:14px}.repository.new.issue .comment.form .metas{min-width:220px}.repository.new.issue .comment.form .metas .filter.menu{max-height:300px;overflow-x:auto}.repository.view.issue .title{padding-bottom:0!important}.repository.view.issue .title h1{font-weight:300;font-size:2.3rem;margin-bottom:5px}.repository.view.issue .title h1 .ui.input{font-size:.5em;vertical-align:top;width:50%;min-width:600px}.repository.view.issue .title h1 .ui.input input{font-size:1.5em;padding:6px 10px}.repository.view.issue .title .index{font-weight:300;color:#aaa;letter-spacing:-1px}.repository.view.issue .title .label{margin-right:10px}.repository.view.issue .title .edit-zone{margin-top:10px}.repository.view.issue .pull-desc code{color:#0166E6}.repository.view.issue .pull.tabular.menu{margin-bottom:10px}.repository.view.issue .pull.tabular.menu .octicon{margin-right:5px}.repository.view.issue .pull.tab.segment{border:none;padding:0;padding-top:10px;box-shadow:none;background-color:inherit}.repository.view.issue .pull .merge.box .avatar{margin-left:10px;margin-top:10px}.repository.view.issue .comment-list:before{display:block;content:"";position:absolute;margin-top:12px;margin-bottom:14px;top:0;bottom:0;left:96px;width:2px;background-color:#f3f3f3;z-index:-1}.repository.view.issue .comment-list .comment .avatar{width:3em}.repository.view.issue .comment-list .comment .tag{color:#767676;margin-top:3px;padding:2px 5px;font-size:12px;border:1px solid rgba(0,0,0,.1);border-radius:3px}.repository.view.issue .comment-list .comment .actions .item{float:left}.repository.view.issue .comment-list .comment .actions .item.tag{margin-right:5px}.repository.view.issue .comment-list .comment .actions .item.action{margin-top:6px;margin-left:10px}.repository.view.issue .comment-list .comment .content{margin-left:4em}.repository.view.issue .comment-list .comment .content>.header{font-weight:400;padding:auto 15px;position:relative;color:#767676;background-color:#f7f7f7;border-bottom:1px solid #eee;border-top-left-radius:3px;border-top-right-radius:3px}.repository.view.issue .comment-list .comment .content>.header:after,.repository.view.issue .comment-list .comment .content>.header:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.view.issue .comment-list .comment .content>.header:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.view.issue .comment-list .comment .content>.header:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.view.issue .comment-list .comment .content>.header .text{max-width:78%;padding-top:10px;padding-bottom:10px}.repository.view.issue .comment-list .comment .content .markdown{font-size:14px}.repository.view.issue .comment-list .comment .content .no-content{color:#767676;font-style:italic}.repository.view.issue .comment-list .comment .content>.bottom.segment{background:#f3f4f5}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.images::after{clear:both;content:' ';display:block}.repository.view.issue .comment-list .comment .content>.bottom.segment a{display:block;float:left;margin:5px;padding:5px;height:150px;border:solid 1px #eee;border-radius:3px;max-width:150px;background-color:#fff}.repository.view.issue .comment-list .comment .content>.bottom.segment a:before{content:' ';display:inline-block;height:100%;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment .ui.image{max-height:100%;width:auto;margin:0;vertical-align:middle}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image{font-size:128px;color:#000}.repository.view.issue .comment-list .comment .content>.bottom.segment span.ui.image:hover{color:#000}.repository.view.issue .comment-list .comment .ui.form .field:first-child{clear:none}.repository.view.issue .comment-list .comment .ui.form .tab.segment{border:none;padding:0;padding-top:10px}.repository.view.issue .comment-list .comment .ui.form textarea{height:200px;font-family:Consolas,monospace}.repository.view.issue .comment-list .comment .edit.buttons{margin-top:10px}.repository.view.issue .comment-list .event{position:relative;margin:15px 0 15px 79px;padding-left:25px}.repository.view.issue .comment-list .event .octicon{width:30px;float:left;text-align:center}.repository.view.issue .comment-list .event .octicon.octicon-circle-slash{margin-top:5px;margin-left:-34.5px;font-size:20px;color:#bd2c00}.repository.view.issue .comment-list .event .octicon.octicon-primitive-dot{margin-left:-28.5px;margin-right:-1px;font-size:30px;color:#6cc644}.repository.view.issue .comment-list .event .octicon.octicon-bookmark{margin-top:3px;margin-left:-31px;margin-right:-1px;font-size:25px}.repository.view.issue .comment-list .event .detail{font-size:.9rem;margin-top:5px;margin-left:35px}.repository.view.issue .comment-list .event .detail .octicon.octicon-git-commit{margin-top:2px}.repository.view.issue .ui.segment.metas{margin-top:-3px}.repository.view.issue .ui.participants img{margin-top:5px;margin-right:5px}.repository .comment.form .ui.comments{margin-top:-12px;max-width:100%}.repository .comment.form .content .field:first-child{clear:none}.repository .comment.form .content .form:after,.repository .comment.form .content .form:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository .comment.form .content .form:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository .comment.form .content .form:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository .comment.form .content .form:after{border-right-color:#fff}.repository .comment.form .content .tab.segment{border:none;padding:0;padding-top:10px}.repository .comment.form .content textarea{height:200px;font-family:Consolas,monospace}.repository .label.list{list-style:none;padding-top:15px}.repository .label.list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .label.list .item a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .label.list .item a:hover{color:#000}.repository .label.list .item a.open-issues{margin-right:30px}.repository .label.list .item .ui.label{font-size:1em}.repository .milestone.list{list-style:none;padding-top:15px}.repository .milestone.list>.item{padding-top:10px;padding-bottom:10px;border-bottom:1px dashed #AAA}.repository .milestone.list>.item>a{padding-top:5px;padding-right:10px;color:#000}.repository .milestone.list>.item>a:hover{color:#4078c0}.repository .milestone.list>.item .ui.progress{width:40%;padding:0;border:0;margin:0}.repository .milestone.list>.item .ui.progress .bar{height:20px}.repository .milestone.list>.item .meta{color:#999;padding-top:5px}.repository .milestone.list>.item .meta .issue-stats .octicon{padding-left:5px}.repository .milestone.list>.item .meta .overdue{color:red}.repository .milestone.list>.item .operate{margin-top:-15px}.repository .milestone.list>.item .operate>a{font-size:15px;padding-top:5px;padding-right:10px;color:#666}.repository .milestone.list>.item .operate>a:hover{color:#000}.repository .milestone.list>.item .content{padding-top:10px}.repository.new.milestone textarea{height:200px}.repository.new.milestone #deadline{width:150px}.repository.compare.pull .choose.branch .octicon{padding-right:10px}.repository.compare.pull .comment.form .content:after,.repository.compare.pull .comment.form .content:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}.repository.compare.pull .comment.form .content:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}.repository.compare.pull .comment.form .content:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}.repository.compare.pull .comment.form .content:after{border-right-color:#fff}.repository .filter.dropdown .menu{margin-top:1px!important}.repository.commits .header .search input{font-weight:400;padding:5px 10px}.repository #commits-table thead th:first-of-type{padding-left:15px}.repository #commits-table thead .sha{width:140px}.repository #commits-table thead .shatd{text-align:center}.repository #commits-table td.sha .sha.label{margin:0}.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #BBB}.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#FAFAFA;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #BBB;border-top-left-radius:0;border-bottom-left-radius:0}.repository #commits-table td.sha .sha.label.isSigned.isVerified,.repository #repo-files-table .sha.label.isSigned.isVerified{border:1px solid #21BA45;background:#21BA4518}.repository #commits-table td.sha .sha.label.isSigned.isVerified .detail.icon,.repository #repo-files-table .sha.label.isSigned.isVerified .detail.icon{border-left:1px solid #21BA4580}.repository .diff-detail-box{margin:15px 0;line-height:30px}.repository .diff-detail-box ol{clear:both;padding-left:0;margin-top:5px;margin-bottom:28px}.repository .diff-detail-box ol li{list-style:none;padding-bottom:4px;margin-bottom:4px;border-bottom:1px dashed #DDD;padding-left:6px}.repository .diff-detail-box span.status{display:inline-block;width:12px;height:12px;margin-right:8px;vertical-align:middle}.repository .diff-detail-box span.status.modify{background-color:#f0db88}.repository .diff-detail-box span.status.add{background-color:#b4e2b4}.repository .diff-detail-box span.status.del{background-color:#e9aeae}.repository .diff-detail-box span.status.rename{background-color:#dad8ff}.repository .diff-detail-box .ui.right{margin-bottom:15px}.repository .diff-box .header{display:flex;align-items:center}.repository .diff-box .header .count{margin-right:12px;font-size:13px;flex:0 0 auto}.repository .diff-box .header .count .bar{background-color:#bd2c00;height:12px;width:40px;display:inline-block;margin:2px 4px 0 4px;vertical-align:text-top}.repository .diff-box .header .count .bar .add{background-color:#55a532;height:12px}.repository .diff-box .header .file{flex:1;color:#888;word-break:break-all}.repository .diff-box .header .button{margin:-5px 0 -5px 12px;padding:8px 10px;flex:0 0 auto}.repository .diff-file-box .header{background-color:#f7f7f7}.repository .diff-file-box .file-body.file-code .lines-num{text-align:right;color:#A7A7A7;background:#fafafa;width:1%;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;vertical-align:top}.repository .diff-file-box .file-body.file-code .lines-num span.fold{display:block;text-align:center}.repository .diff-file-box .file-body.file-code .lines-num-old{border-right:1px solid #DDD}.repository .diff-file-box .code-diff{font-size:12px}.repository .diff-file-box .code-diff td{padding:0;padding-left:10px;border-top:none}.repository .diff-file-box .code-diff pre{margin:0}.repository .diff-file-box .code-diff .lines-num{border-color:#d4d4d5;border-right-width:1px;border-right-style:solid;padding:0 5px}.repository .diff-file-box .code-diff tbody tr td.halfwidth{width:49%}.repository .diff-file-box .code-diff tbody tr td.tag-code,.repository .diff-file-box .code-diff tbody tr.tag-code td{background-color:#F0F0F0!important;border-color:#D2CECE!important;padding-top:8px;padding-bottom:8px}.repository .diff-file-box .code-diff tbody tr .removed-code{background-color:#f99}.repository .diff-file-box .code-diff tbody tr .added-code{background-color:#9f9}.repository .diff-file-box .code-diff-unified tbody tr.del-code td{background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-unified tbody tr.add-code td{background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split table,.repository .diff-file-box .code-diff-split tbody{width:100%}.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4){background-color:#fafafa}.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2){background-color:#ffe0e0!important;border-color:#f1c0c0!important}.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4){background-color:#d6fcd6!important;border-color:#c1e9c1!important}.repository .diff-file-box .code-diff-split tbody tr td:nth-child(3){border-left-width:1px;border-left-style:solid}.repository .diff-file-box.file-content{clear:right}.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}.repository .repo-search-result{padding-top:10px;padding-bottom:10px}.repository .repo-search-result .lines-num a{color:inherit}.repository.quickstart .guide .item{padding:1em}.repository.quickstart .guide .item small{font-weight:400}.repository.quickstart .guide .clone.button:first-child{border-radius:.28571429rem 0 0 .28571429rem}.repository.quickstart .guide .ui.action.small.input{width:100%}.repository.quickstart .guide #repo-clone-url{border-radius:0;padding:5px 10px;font-size:1.2em}.repository.release #release-list{border-top:1px solid #DDD;margin-top:20px;padding-top:15px}.repository.release #release-list>li{list-style:none}.repository.release #release-list>li .detail,.repository.release #release-list>li .meta{padding-top:30px;padding-bottom:40px}.repository.release #release-list>li .meta{text-align:right;position:relative}.repository.release #release-list>li .meta .tag:not(.icon){display:block;margin-top:15px}.repository.release #release-list>li .meta .commit{display:block;margin-top:10px}.repository.release #release-list>li .detail{border-left:1px solid #DDD}.repository.release #release-list>li .detail .author img{margin-bottom:-3px}.repository.release #release-list>li .detail .download{margin-top:20px}.repository.release #release-list>li .detail .download>a .octicon{margin-left:5px;margin-right:5px}.repository.release #release-list>li .detail .download .list{padding-left:0;border-top:1px solid #eee}.repository.release #release-list>li .detail .download .list li{list-style:none;display:block;padding-top:8px;padding-bottom:8px;border-bottom:1px solid #eee}.repository.release #release-list>li .detail .dot{width:9px;height:9px;background-color:#ccc;z-index:999;position:absolute;display:block;left:-5px;top:40px;border-radius:6px;border:1px solid #FFF}.repository.new.release .target{min-width:500px}.repository.new.release .target #tag-name{margin-top:-4px}.repository.new.release .target .at{margin-left:-5px;margin-right:5px}.repository.new.release .target .dropdown.icon{margin:0;padding-top:3px}.repository.new.release .target .selection.dropdown{padding-top:10px;padding-bottom:10px}.repository.new.release .prerelease.field{margin-bottom:0}.repository.forks .list{margin-top:0}.repository.forks .list .item{padding-top:10px;padding-bottom:10px;border-bottom:1px solid #DDD}.repository.forks .list .item .ui.avatar{float:left;margin-right:5px}.repository.forks .list .item .link{padding-top:5px}.repository.wiki.start .ui.segment{padding-top:70px;padding-bottom:100px}.repository.wiki.start .ui.segment .mega-octicon{font-size:48px}.repository.wiki.new .CodeMirror .CodeMirror-code{font-family:Consolas,monospace}.repository.wiki.new .CodeMirror .CodeMirror-code .cm-comment{background:inherit}.repository.wiki.new .editor-preview{background-color:#fff}.repository.wiki.view .choose.page{margin-top:-5px}.repository.wiki.view .ui.sub.header{text-transform:none}.repository.wiki.view>.markdown{padding:15px 30px}.repository.wiki.view>.markdown h1:first-of-type,.repository.wiki.view>.markdown h2:first-of-type,.repository.wiki.view>.markdown h3:first-of-type,.repository.wiki.view>.markdown h4:first-of-type,.repository.wiki.view>.markdown h5:first-of-type,.repository.wiki.view>.markdown h6:first-of-type{margin-top:0}@media only screen and (max-width:767px){.repository.wiki .dividing.header .stackable.grid .button{margin-top:2px;margin-bottom:2px}}.repository.settings.collaboration .collaborator.list{padding:0}.repository.settings.collaboration .collaborator.list>.item{margin:0;line-height:2em}.repository.settings.collaboration .collaborator.list>.item:not(:last-child){border-bottom:1px solid #DDD}.repository.settings.collaboration #repo-collab-form #search-user-box .results{left:7px}.repository.settings.collaboration #repo-collab-form .ui.button{margin-left:5px;margin-top:-3px}.repository.settings.branches .protected-branches .selection.dropdown{width:300px}.repository.settings.branches .protected-branches .item{border:1px solid #eaeaea;padding:10px 15px}.repository.settings.branches .protected-branches .item:not(:last-child){border-bottom:0}.repository.settings.branches .branch-protection .help{margin-left:26px;padding-top:0}.repository.settings.branches .branch-protection .fields{margin-left:20px;display:block}.repository.settings.branches .branch-protection .whitelist{margin-left:26px}.repository.settings.branches .branch-protection .whitelist .dropdown img{display:inline-block}.repository.settings.webhook .events .column{padding-bottom:0}.repository.settings.webhook .events .help{font-size:13px;margin-left:26px;padding-top:0}.repository .ui.attached.isSigned.isVerified:not(.positive){border-left:1px solid #A3C293;border-right:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified.top:not(.positive){border-top:1px solid #A3C293}.repository .ui.attached.isSigned.isVerified:not(.positive):last-child{border-bottom:1px solid #A3C293}.repository .ui.segment.sub-menu{padding:7px;line-height:0}.repository .ui.segment.sub-menu .list{width:100%;display:flex}.repository .ui.segment.sub-menu .list .item{width:100%;border-radius:3px}.repository .ui.segment.sub-menu .list .item a{color:#000}.repository .ui.segment.sub-menu .list .item a:hover{color:#666}.repository .ui.segment.sub-menu .list .item.active{background:rgba(0,0,0,.05)}.repository .segment.reactions.dropdown .menu,.repository .select-reaction.dropdown .menu{right:0!important;left:auto!important}.repository .segment.reactions.dropdown .menu>.header,.repository .select-reaction.dropdown .menu>.header{margin:.75rem 0 .5rem}.repository .segment.reactions.dropdown .menu>.item,.repository .select-reaction.dropdown .menu>.item{float:left;padding:.5rem .5rem!important}.repository .segment.reactions.dropdown .menu>.item img.emoji,.repository .select-reaction.dropdown .menu>.item img.emoji{margin-right:0}.repository .segment.reactions{padding:.3em 1em}.repository .segment.reactions .ui.label{padding:.4em}.repository .segment.reactions .ui.label.disabled{cursor:default}.repository .segment.reactions .ui.label>img{height:1.5em!important}.repository .segment.reactions .select-reaction{float:none}.repository .segment.reactions .select-reaction:not(.active) a{display:none}.repository .segment.reactions:hover .select-reaction a{display:block}.user-cards .list{padding:0}.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}.user-cards .list .item .meta{margin-top:5px}#search-repo-box .results .result .image,#search-user-box .results .result .image{float:left;margin-right:8px;width:2em;height:2em}#search-repo-box .results .result .content,#search-user-box .results .result .content{margin:6px 0}#issue-actions{display:none}.issue.list{list-style:none;padding-top:15px}.issue.list>.item{padding-top:15px;padding-bottom:10px;border-bottom:1px dashed #AAA}.issue.list>.item .title{color:#444;font-size:15px;font-weight:700;margin:0 6px}.issue.list>.item .title:hover{color:#000}.issue.list>.item .comment{padding-right:10px;color:#666}.issue.list>.item .desc{padding-top:5px;color:#999}.issue.list>.item .desc .checklist{padding-left:5px}.issue.list>.item .desc .checklist .progress-bar{margin-left:2px;width:80px;height:6px;display:inline-block;background-color:#eee;overflow:hidden;border-radius:3px;vertical-align:2px!important}.issue.list>.item .desc .checklist .progress-bar .progress{background-color:#ccc;display:block;height:100%}.issue.list>.item .desc a.milestone{padding-left:5px;color:#999!important}.issue.list>.item .desc a.milestone:hover{color:#000!important}.issue.list>.item .desc .assignee{margin-top:-5px;margin-right:5px}.issue.list>.item .desc .overdue{color:red}.page.buttons{padding-top:15px}.ui.form .dropzone{width:100%;margin-bottom:10px;border:2px dashed #0087F7;box-shadow:none!important}.ui.form .dropzone .dz-error-message{top:140px}.settings .content{margin-top:2px}.settings .content .segment,.settings .content>.header{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.settings .list>.item .green{color:#21BA45!important}.settings .list>.item:not(:first-child){border-top:1px solid #eaeaea;padding:1rem;margin:15px -1rem -1rem -1rem}.settings .list>.item>.mega-octicon{display:table-cell}.settings .list>.item>.mega-octicon+.content{display:table-cell;padding:0 0 0 .5em;vertical-align:top}.settings .list>.item .info{margin-top:10px}.settings .list>.item .info .tab.segment{border:none;padding:10px 0 0}.settings .list.key .meta{padding-top:5px;color:#666}.settings .list.email>.item:not(:first-child){min-height:60px}.settings .list.collaborator>.item{padding:0}.ui.vertical.menu .header.item{font-size:1.1em;background:#f0f0f0}.edit-label.modal .form .column,.new-label.segment .form .column{padding-right:0}.edit-label.modal .form .buttons,.new-label.segment .form .buttons{margin-left:auto;padding-top:15px}.edit-label.modal .form .color.picker.column,.new-label.segment .form .color.picker.column{width:auto}.edit-label.modal .form .color.picker.column .color-picker,.new-label.segment .form .color.picker.column .color-picker{height:35px;width:auto;padding-left:30px}.edit-label.modal .form .minicolors-swatch.minicolors-sprite,.new-label.segment .form .minicolors-swatch.minicolors-sprite{top:10px;left:10px;width:15px;height:15px}.edit-label.modal .form .precolors,.new-label.segment .form .precolors{padding-left:0;padding-right:0;margin:3px 10px auto 10px;width:120px}.edit-label.modal .form .precolors .color,.new-label.segment .form .precolors .color{float:left;width:15px;height:15px}#avatar-arrow:after,#avatar-arrow:before{right:100%;top:20px;border:solid transparent;content:" ";height:0;width:0;position:absolute;pointer-events:none}#avatar-arrow:before{border-right-color:#D4D4D5;border-width:9px;margin-top:-9px}#avatar-arrow:after{border-right-color:#f7f7f7;border-width:8px;margin-top:-8px}#delete-repo-modal .ui.message,#transfer-repo-modal .ui.message{width:100%!important}.tab-size-1{tab-size:1!important;-moz-tab-size:1!important}.tab-size-2{tab-size:2!important;-moz-tab-size:2!important}.tab-size-3{tab-size:3!important;-moz-tab-size:3!important}.tab-size-4{tab-size:4!important;-moz-tab-size:4!important}.tab-size-5{tab-size:5!important;-moz-tab-size:5!important}.tab-size-6{tab-size:6!important;-moz-tab-size:6!important}.tab-size-7{tab-size:7!important;-moz-tab-size:7!important}.tab-size-8{tab-size:8!important;-moz-tab-size:8!important}.tab-size-9{tab-size:9!important;-moz-tab-size:9!important}.tab-size-10{tab-size:10!important;-moz-tab-size:10!important}.tab-size-11{tab-size:11!important;-moz-tab-size:11!important}.tab-size-12{tab-size:12!important;-moz-tab-size:12!important}.tab-size-13{tab-size:13!important;-moz-tab-size:13!important}.tab-size-14{tab-size:14!important;-moz-tab-size:14!important}.tab-size-15{tab-size:15!important;-moz-tab-size:15!important}.tab-size-16{tab-size:16!important;-moz-tab-size:16!important}.stats-table{display:table;width:100%}.stats-table .table-cell{display:table-cell}.stats-table .table-cell.tiny{height:.5em}tbody.commit-list{vertical-align:baseline}.commit-body{white-space:pre-wrap}@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}}#topic_edit{margin-top:5px;display:none}#repo-topic{margin-top:5px}.CodeMirror{font:14px Consolas,"Liberation Mono",Menlo,Courier,monospace}.CodeMirror.cm-s-default{border-radius:3px;padding:0!important}.CodeMirror .cm-comment{background:inherit!important}.repository.file.editor .tab[data-tab=write]{padding:0!important}.repository.file.editor .tab[data-tab=write] .editor-toolbar{border:none!important}.repository.file.editor .tab[data-tab=write] .CodeMirror{border-left:none;border-right:none;border-bottom:none}.organization{padding-top:15px;padding-bottom:80px}.organization .head .ui.header .text{vertical-align:middle;font-size:1.6rem;margin-left:15px}.organization .head .ui.header .ui.right{margin-top:5px}.organization.new.org form{margin:auto}.organization.new.org form .ui.message{text-align:center}@media only screen and (min-width:768px){.organization.new.org form{width:800px!important}.organization.new.org form .header{padding-left:280px!important}.organization.new.org form .inline.field>label{text-align:right;width:250px!important;word-wrap:break-word}.organization.new.org form .help{margin-left:265px!important}.organization.new.org form .optional .title{margin-left:250px!important}.organization.new.org form input,.organization.new.org form textarea{width:50%!important}}@media only screen and (max-width:767px){.organization.new.org form .optional .title{margin-left:15px}.organization.new.org form .inline.field>label{display:block}}.organization.new.org form .header{padding-left:0!important;text-align:center}.organization.options input{min-width:300px}.organization.profile #org-avatar{width:100px;height:100px;margin-right:15px}.organization.profile #org-info .ui.header{font-size:36px;margin-bottom:0}.organization.profile #org-info .desc{font-size:16px;margin-bottom:10px}.organization.profile #org-info .meta .item{display:inline-block;margin-right:10px}.organization.profile #org-info .meta .item .icon{margin-right:5px}.organization.profile .ui.top.header .ui.right{margin-top:0}.organization.profile .teams .item{padding:10px 15px}.organization.profile .members .ui.avatar,.organization.teams .members .ui.avatar{width:48px;height:48px;margin-right:5px}.organization.invite #invite-box{margin:auto;margin-top:50px;width:500px!important}.organization.invite #invite-box #search-user-box input{margin-left:0;width:300px}.organization.invite #invite-box .ui.button{margin-left:5px;margin-top:-3px}.organization.members .list .item{margin-left:0;margin-right:0;border-bottom:1px solid #eee}.organization.members .list .item .ui.avatar{width:48px;height:48px}.organization.members .list .item .meta{line-height:24px}.organization.teams .detail .item{padding:10px 15px}.organization.teams .detail .item:not(:last-child){border-bottom:1px solid #eee}.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #DDD}.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}.user:not(.icon){padding-top:15px;padding-bottom:80px}.user.profile .ui.card .username{display:block}.user.profile .ui.card .extra.content{padding:0}.user.profile .ui.card .extra.content ul{margin:0;padding:0}.user.profile .ui.card .extra.content ul li{padding:10px;list-style:none}.user.profile .ui.card .extra.content ul li:not(:last-child){border-bottom:1px solid #eaeaea}.user.profile .ui.card .extra.content ul li .octicon{margin-left:1px;margin-right:5px}.user.profile .ui.card .extra.content ul li.follow .ui.button{width:100%}.user.profile .ui.repository.list{margin-top:25px}.user.followers .header.name{font-size:20px;line-height:24px;vertical-align:middle}.user.followers .follow .ui.button{padding:8px 15px}.user.notification .octicon{float:left;font-size:2em}.user.notification .content{float:left;margin-left:7px}.user.notification table form{display:inline-block}.user.notification table button{padding:3px 3px 3px 5px}.user.notification table tr{cursor:pointer}.user.notification .octicon.green{color:#21ba45}.user.notification .octicon.red{color:#d01919}.user.notification .octicon.purple{color:#a333c8}.user.notification .octicon.blue{color:#2185d0}.user.link-account:not(.icon){padding-top:15px;padding-bottom:5px}.user.settings .iconFloat{float:left}.dashboard{padding-top:15px;padding-bottom:80px}.dashboard.feeds .context.user.menu,.dashboard.issues .context.user.menu{z-index:101;min-width:200px}.dashboard.feeds .context.user.menu .ui.header,.dashboard.issues .context.user.menu .ui.header{font-size:1rem;text-transform:none}.dashboard.feeds .filter.menu .item,.dashboard.issues .filter.menu .item{text-align:left}.dashboard.feeds .filter.menu .item .text,.dashboard.issues .filter.menu .item .text{height:16px;vertical-align:middle}.dashboard.feeds .filter.menu .item .text.truncate,.dashboard.issues .filter.menu .item .text.truncate{width:85%}.dashboard.feeds .filter.menu .item .floating.label,.dashboard.issues .filter.menu .item .floating.label{top:7px;left:90%;width:15%}.dashboard.feeds .filter.menu .jump.item,.dashboard.issues .filter.menu .jump.item{margin:1px;padding-right:0}.dashboard.feeds .filter.menu .menu,.dashboard.issues .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}.dashboard.feeds .right.stackable.menu>.item.active,.dashboard.issues .right.stackable.menu>.item.active{color:#d9453d}.dashboard .dashboard-repos{margin:0 1px}.feeds .news>.ui.grid{margin-left:auto;margin-right:auto}.feeds .news .ui.avatar{margin-top:13px}.feeds .news p{line-height:1em}.feeds .news .time-since{font-size:13px}.feeds .news .issue.title{width:80%}.feeds .news .push.news .content ul{font-size:13px;list-style:none;padding-left:10px}.feeds .news .push.news .content ul img{margin-bottom:-2px}.feeds .news .push.news .content ul .text.truncate{width:80%;margin-bottom:-5px}.feeds .news .commit-id{font-family:Consolas,monospace}.feeds .news code{padding:1px;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px;word-break:break-all}.feeds .list .header .ui.label{margin-top:-4px;padding:4px 5px;font-weight:400}.feeds .list .header .plus.icon{margin-top:5px}.feeds .list ul{list-style:none;margin:0;padding-left:0}.feeds .list ul li:not(:last-child){border-bottom:1px solid #EAEAEA}.feeds .list ul li.private{background-color:#fcf8e9}.feeds .list ul li a{padding:6px 1.2em;display:block}.feeds .list ul li a .octicon{color:#888}.feeds .list ul li a .octicon.rear{font-size:15px}.feeds .list ul li a .star-num{font-size:12px}.feeds .list .repo-owner-name-list .item-name{max-width:70%;margin-bottom:-4px}.feeds .list #collaborative-repo-list .owner-and-repo{max-width:80%;margin-bottom:-5px}.feeds .list #collaborative-repo-list .owner-name{max-width:120px;margin-bottom:-5px}.admin{padding-top:15px;padding-bottom:80px}.admin .table.segment{padding:0;font-size:13px}.admin .table.segment:not(.striped){padding-top:5px}.admin .table.segment:not(.striped) thead th:last-child{padding-right:5px!important}.admin .table.segment th{padding-top:5px;padding-bottom:5px}.admin .table.segment:not(.select) td:first-of-type,.admin .table.segment:not(.select) th:first-of-type{padding-left:15px!important}.admin .ui.header,.admin .ui.segment{box-shadow:0 1px 2px 0 rgba(34,36,38,.15)}.admin.user .email{max-width:200px}.admin dl.admin-dl-horizontal{padding:20px;margin:0}.admin dl.admin-dl-horizontal dd{margin-left:275px}.admin dl.admin-dl-horizontal dt{font-weight:bolder;float:left;width:285px;clear:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin.config #test-mail-btn{margin-left:5px}.explore{padding-top:15px;padding-bottom:80px}.explore .navbar{justify-content:center;padding-top:15px!important;margin-top:-15px!important;margin-bottom:15px!important;background-color:#FAFAFA!important;border-width:1px!important}.explore .navbar .octicon{width:16px;text-align:center;margin-right:5px}.ui.repository.list .item{padding-bottom:25px}.ui.repository.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.repository.list .item .ui.header{font-size:1.5rem;padding-bottom:10px}.ui.repository.list .item .ui.header .name{word-break:break-all}.ui.repository.list .item .ui.header .metas{color:#888;font-size:14px;font-weight:400}.ui.repository.list .item .ui.header .metas span:not(:last-child){margin-right:5px}.ui.repository.list .item .time{font-size:12px;color:grey}.ui.repository.branches .time{font-size:12px;color:grey}.ui.user.list .item{padding-bottom:25px}.ui.user.list .item:not(:first-child){border-top:1px solid #eee;padding-top:25px}.ui.user.list .item .ui.avatar.image{width:40px;height:40px}.ui.user.list .item .description{margin-top:5px}.ui.user.list .item .description .octicon:not(:first-child){margin-left:5px}.ui.user.list .item .description a{color:#333}.ui.user.list .item .description a:hover{text-decoration:underline} \ No newline at end of file diff --git a/public/js/index.js b/public/js/index.js index 6045d3276d8..78fc202a9b3 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -179,81 +179,115 @@ function initCommentForm() { initBranchSelector(); initCommentPreviewTab($('.comment.form')); - // Labels - var $list = $('.ui.labels.list'); - var $noSelect = $list.find('.no-select'); - var $labelMenu = $('.select-label .menu'); - var hasLabelUpdateAction = $labelMenu.data('action') == 'update'; - - $('.select-label').dropdown('setting', 'onHide', function(){ - if (hasLabelUpdateAction) { - location.reload(); - } - }); - - $labelMenu.find('.item:not(.no-select)').click(function () { - if ($(this).hasClass('checked')) { - $(this).removeClass('checked'); - $(this).find('.octicon').removeClass('octicon-check'); + // Listsubmit + function initListSubmits(selector, outerSelector) { + var $list = $('.ui.' + outerSelector + '.list'); + var $noSelect = $list.find('.no-select'); + var $listMenu = $('.' + selector + ' .menu'); + var hasLabelUpdateAction = $listMenu.data('action') == 'update'; + + $('.' + selector).dropdown('setting', 'onHide', function(){ + hasLabelUpdateAction = $listMenu.data('action') == 'update'; // Update the var if (hasLabelUpdateAction) { - updateIssuesMeta( - $labelMenu.data('update-url'), - "detach", - $labelMenu.data('issue-id'), - $(this).data('id') - ); + location.reload(); } - } else { - $(this).addClass('checked'); - $(this).find('.octicon').addClass('octicon-check'); - if (hasLabelUpdateAction) { + }); + + $listMenu.find('.item:not(.no-select)').click(function () { + + // we don't need the action attribute when updating assignees + if (selector == 'select-assignees-modify') { + + // UI magic. We need to do this here, otherwise it would destroy the functionality of + // adding/removing labels + if ($(this).hasClass('checked')) { + $(this).removeClass('checked'); + $(this).find('.octicon').removeClass('octicon-check'); + } else { + $(this).addClass('checked'); + $(this).find('.octicon').addClass('octicon-check'); + } + updateIssuesMeta( - $labelMenu.data('update-url'), - "attach", - $labelMenu.data('issue-id'), + $listMenu.data('update-url'), + "", + $listMenu.data('issue-id'), $(this).data('id') ); + $listMenu.data('action', 'update'); // Update to reload the page when we updated items + return false; } - } - var labelIds = []; - $(this).parent().find('.item').each(function () { if ($(this).hasClass('checked')) { - labelIds.push($(this).data('id')); - $($(this).data('id-selector')).removeClass('hide'); + $(this).removeClass('checked'); + $(this).find('.octicon').removeClass('octicon-check'); + if (hasLabelUpdateAction) { + updateIssuesMeta( + $listMenu.data('update-url'), + "detach", + $listMenu.data('issue-id'), + $(this).data('id') + ); + } } else { - $($(this).data('id-selector')).addClass('hide'); + $(this).addClass('checked'); + $(this).find('.octicon').addClass('octicon-check'); + if (hasLabelUpdateAction) { + updateIssuesMeta( + $listMenu.data('update-url'), + "attach", + $listMenu.data('issue-id'), + $(this).data('id') + ); + } } + + var listIds = []; + $(this).parent().find('.item').each(function () { + if ($(this).hasClass('checked')) { + listIds.push($(this).data('id')); + $($(this).data('id-selector')).removeClass('hide'); + } else { + $($(this).data('id-selector')).addClass('hide'); + } + }); + if (listIds.length == 0) { + $noSelect.removeClass('hide'); + } else { + $noSelect.addClass('hide'); + } + $($(this).parent().data('id')).val(listIds.join(",")); + return false; }); - if (labelIds.length == 0) { + $listMenu.find('.no-select.item').click(function () { + if (hasLabelUpdateAction || selector == 'select-assignees-modify') { + updateIssuesMeta( + $listMenu.data('update-url'), + "clear", + $listMenu.data('issue-id'), + "" + ); + $listMenu.data('action', 'update'); // Update to reload the page when we updated items + } + + $(this).parent().find('.item').each(function () { + $(this).removeClass('checked'); + $(this).find('.octicon').removeClass('octicon-check'); + }); + + $list.find('.item').each(function () { + $(this).addClass('hide'); + }); $noSelect.removeClass('hide'); - } else { - $noSelect.addClass('hide'); - } - $($(this).parent().data('id')).val(labelIds.join(",")); - return false; - }); - $labelMenu.find('.no-select.item').click(function () { - if (hasLabelUpdateAction) { - updateIssuesMeta( - $labelMenu.data('update-url'), - "clear", - $labelMenu.data('issue-id'), - "" - ); - } + $($(this).parent().data('id')).val(''); - $(this).parent().find('.item').each(function () { - $(this).removeClass('checked'); - $(this).find('.octicon').removeClass('octicon-check'); }); + } - $list.find('.item').each(function () { - $(this).addClass('hide'); - }); - $noSelect.removeClass('hide'); - $($(this).parent().data('id')).val(''); - }); + // Init labels and assignees + initListSubmits('select-label', 'labels'); + initListSubmits('select-assignees', 'assignees'); + initListSubmits('select-assignees-modify', 'assignees'); function selectItem(select_id, input_id) { var $menu = $(select_id + ' .menu'); @@ -2227,7 +2261,11 @@ function initTopicbar() { alert(res.message); } else { viewDiv.children(".topic").remove(); + if (topics.length == 0) { + return + } var topicArray = topics.split(","); + var last = viewDiv.children("a").last(); for (var i=0;i < topicArray.length; i++) { $('
'+topicArray[i]+'
').insertBefore(last) diff --git a/public/less/_base.less b/public/less/_base.less index 95b23e2a85e..6327ebf61fc 100644 --- a/public/less/_base.less +++ b/public/less/_base.less @@ -152,6 +152,10 @@ pre, code { } } + &.floating.label { + z-index: 10; + } + &.menu, &.vertical.menu, &.segment { @@ -167,6 +171,14 @@ pre, code { font-size: .92857143rem; } + &.dropdown .menu>.item>.floating.label { + z-index: 11; + } + + &.dropdown .menu .menu>.item>.floating.label { + z-index: 21; + } + .text { &.red { color: #d95c5c !important; diff --git a/public/less/_repository.less b/public/less/_repository.less index 5f3eda0ede8..efab446978b 100644 --- a/public/less/_repository.less +++ b/public/less/_repository.less @@ -119,8 +119,11 @@ } .octicon { float: left; - margin-left: -5px; - margin-right: -7px; + margin: 5px -7px 0 -5px; + width: 16px; + } + .text{ + margin-left: 0.9em; } .menu { max-height: 300px; diff --git a/public/swagger.v1.json b/public/swagger.v1.json index baacdfdf87a..c5b1baa9ada 100644 --- a/public/swagger.v1.json +++ b/public/swagger.v1.json @@ -1605,7 +1605,7 @@ } } }, - "/repos/{owner}/{repo}/issue/{index}/comments": { + "/repos/{owner}/{repo}/issues": { "get": { "produces": [ "application/json" @@ -1613,8 +1613,8 @@ "tags": [ "issue" ], - "summary": "List all comments on an issue", - "operationId": "issueGetComments", + "summary": "List a repository's issues", + "operationId": "issueListIssues", "parameters": [ { "type": "string", @@ -1630,29 +1630,32 @@ "in": "path", "required": true }, + { + "type": "string", + "description": "whether issue is open or closed", + "name": "state", + "in": "query" + }, { "type": "integer", - "description": "index of the issue", - "name": "id", - "in": "path", - "required": true + "description": "page number of requested issues", + "name": "page", + "in": "query" }, { "type": "string", - "description": "if provided, only comments updated since the specified time are returned.", - "name": "string", + "description": "search string", + "name": "q", "in": "query" } ], "responses": { "200": { - "$ref": "#/responses/CommentList" + "$ref": "#/responses/IssueList" } } - } - }, - "/repos/{owner}/{repo}/issue/{index}/labels": { - "put": { + }, + "post": { "consumes": [ "application/json" ], @@ -1662,8 +1665,8 @@ "tags": [ "issue" ], - "summary": "Replace an issue's labels", - "operationId": "issueReplaceLabels", + "summary": "Create an issue", + "operationId": "issueCreateIssue", "parameters": [ { "type": "string", @@ -1679,39 +1682,31 @@ "in": "path", "required": true }, - { - "type": "integer", - "description": "index of the issue", - "name": "index", - "in": "path", - "required": true - }, { "name": "body", "in": "body", "schema": { - "$ref": "#/definitions/IssueLabelsOption" + "$ref": "#/definitions/CreateIssueOption" } } ], "responses": { - "200": { - "$ref": "#/responses/LabelList" + "201": { + "$ref": "#/responses/Issue" } } - }, - "post": { - "consumes": [ - "application/json" - ], + } + }, + "/repos/{owner}/{repo}/issues/comments": { + "get": { "produces": [ "application/json" ], "tags": [ "issue" ], - "summary": "Add a label to an issue", - "operationId": "issueAddLabel", + "summary": "List all comments in a repository", + "operationId": "issueGetRepoComments", "parameters": [ { "type": "string", @@ -1728,35 +1723,26 @@ "required": true }, { - "type": "integer", - "description": "index of the issue", - "name": "index", - "in": "path", - "required": true - }, - { - "name": "body", - "in": "body", - "schema": { - "$ref": "#/definitions/IssueLabelsOption" - } + "type": "string", + "description": "if provided, only comments updated since the provided time are returned.", + "name": "string", + "in": "query" } ], "responses": { "200": { - "$ref": "#/responses/LabelList" + "$ref": "#/responses/CommentList" } } - }, + } + }, + "/repos/{owner}/{repo}/issues/comments/{id}": { "delete": { - "produces": [ - "application/json" - ], "tags": [ "issue" ], - "summary": "Remove all labels from an issue", - "operationId": "issueClearLabels", + "summary": "Delete a comment", + "operationId": "issueDeleteComment", "parameters": [ { "type": "string", @@ -1774,8 +1760,8 @@ }, { "type": "integer", - "description": "index of the issue", - "name": "index", + "description": "id of comment to delete", + "name": "id", "in": "path", "required": true } @@ -1785,18 +1771,19 @@ "$ref": "#/responses/empty" } } - } - }, - "/repos/{owner}/{repo}/issue/{index}/labels/{id}": { - "delete": { + }, + "patch": { + "consumes": [ + "application/json" + ], "produces": [ "application/json" ], "tags": [ "issue" ], - "summary": "Remove a label from an issue", - "operationId": "issueRemoveLabel", + "summary": "Edit a comment", + "operationId": "issueEditComment", "parameters": [ { "type": "string", @@ -1814,27 +1801,27 @@ }, { "type": "integer", - "description": "index of the issue", - "name": "index", + "description": "id of the comment to edit", + "name": "id", "in": "path", "required": true }, { - "type": "integer", - "description": "id of the label to remove", - "name": "id", - "in": "path", - "required": true + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/EditIssueCommentOption" + } } ], "responses": { - "204": { - "$ref": "#/responses/empty" + "200": { + "$ref": "#/responses/Comment" } } } }, - "/repos/{owner}/{repo}/issues": { + "/repos/{owner}/{repo}/issues/{index}": { "get": { "produces": [ "application/json" @@ -1842,8 +1829,8 @@ "tags": [ "issue" ], - "summary": "List a repository's issues", - "operationId": "issueListIssues", + "summary": "Get an issue", + "operationId": "issueGetIssue", "parameters": [ { "type": "string", @@ -1859,32 +1846,21 @@ "in": "path", "required": true }, - { - "type": "string", - "description": "whether issue is open or closed", - "name": "state", - "in": "query" - }, { "type": "integer", - "description": "page number of requested issues", - "name": "page", - "in": "query" - }, - { - "type": "string", - "description": "search string", - "name": "q", - "in": "query" + "description": "index of the issue to get", + "name": "index", + "in": "path", + "required": true } ], "responses": { "200": { - "$ref": "#/responses/IssueList" + "$ref": "#/responses/Issue" } } }, - "post": { + "patch": { "consumes": [ "application/json" ], @@ -1894,8 +1870,8 @@ "tags": [ "issue" ], - "summary": "Create an issue", - "operationId": "issueCreateIssue", + "summary": "Edit an issue", + "operationId": "issueEditIssue", "parameters": [ { "type": "string", @@ -1911,11 +1887,18 @@ "in": "path", "required": true }, + { + "type": "integer", + "description": "index of the issue to edit", + "name": "index", + "in": "path", + "required": true + }, { "name": "body", "in": "body", "schema": { - "$ref": "#/definitions/CreateIssueOption" + "$ref": "#/definitions/EditIssueOption" } } ], @@ -1926,7 +1909,7 @@ } } }, - "/repos/{owner}/{repo}/issues/comments": { + "/repos/{owner}/{repo}/issues/{index}/comments": { "get": { "produces": [ "application/json" @@ -1934,8 +1917,8 @@ "tags": [ "issue" ], - "summary": "List all comments in a repository", - "operationId": "issueGetRepoComments", + "summary": "List all comments on an issue", + "operationId": "issueGetComments", "parameters": [ { "type": "string", @@ -1951,9 +1934,16 @@ "in": "path", "required": true }, + { + "type": "integer", + "description": "index of the issue", + "name": "id", + "in": "path", + "required": true + }, { "type": "string", - "description": "if provided, only comments updated since the provided time are returned.", + "description": "if provided, only comments updated since the specified time are returned.", "name": "string", "in": "query" } @@ -1963,15 +1953,64 @@ "$ref": "#/responses/CommentList" } } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "issue" + ], + "summary": "Add a comment to an issue", + "operationId": "issueCreateComment", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "index of the issue", + "name": "id", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/CreateIssueOption" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/Comment" + } + } } }, - "/repos/{owner}/{repo}/issues/comments/{id}": { + "/repos/{owner}/{repo}/issues/{index}/comments/{id}": { "delete": { "tags": [ "issue" ], "summary": "Delete a comment", - "operationId": "issueDeleteComment", + "operationId": "issueDeleteCommentDeprecated", + "deprecated": true, "parameters": [ { "type": "string", @@ -1987,6 +2026,13 @@ "in": "path", "required": true }, + { + "type": "integer", + "description": "this parameter is ignored", + "name": "index", + "in": "path", + "required": true + }, { "type": "integer", "description": "id of comment to delete", @@ -2012,7 +2058,8 @@ "issue" ], "summary": "Edit a comment", - "operationId": "issueEditComment", + "operationId": "issueEditCommentDeprecated", + "deprecated": true, "parameters": [ { "type": "string", @@ -2028,6 +2075,13 @@ "in": "path", "required": true }, + { + "type": "integer", + "description": "this parameter is ignored", + "name": "index", + "in": "path", + "required": true + }, { "type": "integer", "description": "id of the comment to edit", @@ -2050,7 +2104,7 @@ } } }, - "/repos/{owner}/{repo}/issues/{index}": { + "/repos/{owner}/{repo}/issues/{index}/labels": { "get": { "produces": [ "application/json" @@ -2058,8 +2112,8 @@ "tags": [ "issue" ], - "summary": "Get an issue", - "operationId": "issueGetIssue", + "summary": "Get an issue's labels", + "operationId": "issueGetLabels", "parameters": [ { "type": "string", @@ -2077,7 +2131,7 @@ }, { "type": "integer", - "description": "index of the issue to get", + "description": "index of the issue", "name": "index", "in": "path", "required": true @@ -2085,11 +2139,14 @@ ], "responses": { "200": { - "$ref": "#/responses/Issue" + "$ref": "#/responses/LabelList" + }, + "404": { + "$ref": "#/responses/notFound" } } }, - "patch": { + "put": { "consumes": [ "application/json" ], @@ -2099,8 +2156,8 @@ "tags": [ "issue" ], - "summary": "Edit an issue", - "operationId": "issueEditIssue", + "summary": "Replace an issue's labels", + "operationId": "issueReplaceLabels", "parameters": [ { "type": "string", @@ -2118,7 +2175,7 @@ }, { "type": "integer", - "description": "index of the issue to edit", + "description": "index of the issue", "name": "index", "in": "path", "required": true @@ -2127,18 +2184,16 @@ "name": "body", "in": "body", "schema": { - "$ref": "#/definitions/EditIssueOption" + "$ref": "#/definitions/IssueLabelsOption" } } ], "responses": { - "201": { - "$ref": "#/responses/Issue" + "200": { + "$ref": "#/responses/LabelList" } } - } - }, - "/repos/{owner}/{repo}/issues/{index}/comments": { + }, "post": { "consumes": [ "application/json" @@ -2149,8 +2204,8 @@ "tags": [ "issue" ], - "summary": "Add a comment to an issue", - "operationId": "issueCreateComment", + "summary": "Add a label to an issue", + "operationId": "issueAddLabel", "parameters": [ { "type": "string", @@ -2169,7 +2224,7 @@ { "type": "integer", "description": "index of the issue", - "name": "id", + "name": "index", "in": "path", "required": true }, @@ -2177,25 +2232,25 @@ "name": "body", "in": "body", "schema": { - "$ref": "#/definitions/CreateIssueOption" + "$ref": "#/definitions/IssueLabelsOption" } } ], "responses": { - "201": { - "$ref": "#/responses/Comment" + "200": { + "$ref": "#/responses/LabelList" } } - } - }, - "/repos/{owner}/{repo}/issues/{index}/comments/{id}": { + }, "delete": { + "produces": [ + "application/json" + ], "tags": [ "issue" ], - "summary": "Delete a comment", - "operationId": "issueDeleteCommentDeprecated", - "deprecated": true, + "summary": "Remove all labels from an issue", + "operationId": "issueClearLabels", "parameters": [ { "type": "string", @@ -2213,17 +2268,10 @@ }, { "type": "integer", - "description": "this parameter is ignored", + "description": "index of the issue", "name": "index", "in": "path", "required": true - }, - { - "type": "integer", - "description": "id of comment to delete", - "name": "id", - "in": "path", - "required": true } ], "responses": { @@ -2231,20 +2279,18 @@ "$ref": "#/responses/empty" } } - }, - "patch": { - "consumes": [ - "application/json" - ], + } + }, + "/repos/{owner}/{repo}/issues/{index}/labels/{id}": { + "delete": { "produces": [ "application/json" ], "tags": [ "issue" ], - "summary": "Edit a comment", - "operationId": "issueEditCommentDeprecated", - "deprecated": true, + "summary": "Remove a label from an issue", + "operationId": "issueRemoveLabel", "parameters": [ { "type": "string", @@ -2262,72 +2308,22 @@ }, { "type": "integer", - "description": "this parameter is ignored", + "description": "index of the issue", "name": "index", "in": "path", "required": true }, { "type": "integer", - "description": "id of the comment to edit", + "description": "id of the label to remove", "name": "id", "in": "path", "required": true - }, - { - "name": "body", - "in": "body", - "schema": { - "$ref": "#/definitions/EditIssueCommentOption" - } - } - ], - "responses": { - "200": { - "$ref": "#/responses/Comment" - } - } - } - }, - "/repos/{owner}/{repo}/issues/{index}/labels": { - "get": { - "produces": [ - "application/json" - ], - "tags": [ - "issue" - ], - "summary": "Get an issue's labels", - "operationId": "issueGetLabels", - "parameters": [ - { - "type": "string", - "description": "owner of the repo", - "name": "owner", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "name of the repo", - "name": "repo", - "in": "path", - "required": true - }, - { - "type": "integer", - "description": "index of the issue", - "name": "index", - "in": "path", - "required": true } ], "responses": { - "200": { - "$ref": "#/responses/LabelList" - }, - "404": { - "$ref": "#/responses/notFound" + "204": { + "$ref": "#/responses/empty" } } } diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index cc033554f3a..211d8045a45 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -178,25 +178,22 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) { DeadlineUnix: deadlineUnix, } - if ctx.Repo.IsWriter() { - if len(form.Assignee) > 0 { - assignee, err := models.GetUserByName(form.Assignee) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", form.Assignee)) - } else { - ctx.Error(500, "GetUserByName", err) - } - return - } - issue.AssigneeID = assignee.ID + // Get all assignee IDs + assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err)) + } else { + ctx.Error(500, "AddAssigneeByName", err) } - issue.MilestoneID = form.Milestone - } else { - form.Labels = nil + return } - if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, nil); err != nil { + if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil { + if models.IsErrUserDoesNotHaveAccessToRepo(err) { + ctx.Error(400, "UserDoesNotHaveAccessToRepo", err) + return + } ctx.Error(500, "NewIssue", err) return } @@ -209,7 +206,6 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) { } // Refetch from database to assign some automatic values - var err error issue, err = models.GetIssueByID(issue.ID) if err != nil { ctx.Error(500, "GetIssueByID", err) @@ -272,6 +268,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) { issue.Content = *form.Body } + // Update the deadline var deadlineUnix util.TimeStamp if form.Deadline != nil && !form.Deadline.IsZero() { deadlineUnix = util.TimeStamp(form.Deadline.Unix()) @@ -282,28 +279,28 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) { return } - if ctx.Repo.IsWriter() && form.Assignee != nil && - (issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(*form.Assignee)) { - if len(*form.Assignee) == 0 { - issue.AssigneeID = 0 - } else { - assignee, err := models.GetUserByName(*form.Assignee) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", *form.Assignee)) - } else { - ctx.Error(500, "GetUserByName", err) - } - return - } - issue.AssigneeID = assignee.ID + // Add/delete assignees + + // Deleting is done the Github way (quote from their api documentation): + // https://developer.github.com/v3/issues/#edit-an-issue + // "assignees" (array): Logins for Users to assign to this issue. + // Pass one or more user logins to replace the set of assignees on this Issue. + // Send an empty array ([]) to clear all assignees from the Issue. + + if ctx.Repo.IsWriter() && (form.Assignees != nil || form.Assignee != nil) { + + oneAssignee := "" + if form.Assignee != nil { + oneAssignee = *form.Assignee } - if err = models.UpdateIssueUserByAssignee(issue); err != nil { - ctx.Error(500, "UpdateIssueUserByAssignee", err) + err = models.UpdateAPIAssignee(issue, oneAssignee, form.Assignees, ctx.User) + if err != nil { + ctx.Error(500, "UpdateAPIAssignee", err) return } } + if ctx.Repo.IsWriter() && form.Milestone != nil && issue.MilestoneID != *form.Milestone { oldMilestoneID := issue.MilestoneID diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 5fb50550f07..a9258849ead 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -15,7 +15,7 @@ import ( // ListIssueComments list all the comments of an issue func ListIssueComments(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/issue/{index}/comments issue issueGetComments + // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/comments issue issueGetComments // --- // summary: List all comments on an issue // produces: diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 95ea19d54d7..3657f02c652 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -58,7 +58,7 @@ func ListIssueLabels(ctx *context.APIContext) { // AddIssueLabels add labels for an issue func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { - // swagger:operation POST /repos/{owner}/{repo}/issue/{index}/labels issue issueAddLabel + // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/labels issue issueAddLabel // --- // summary: Add a label to an issue // consumes: @@ -129,7 +129,7 @@ func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { // DeleteIssueLabel delete a label for an issue func DeleteIssueLabel(ctx *context.APIContext) { - // swagger:operation DELETE /repos/{owner}/{repo}/issue/{index}/labels/{id} issue issueRemoveLabel + // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} issue issueRemoveLabel // --- // summary: Remove a label from an issue // produces: @@ -193,7 +193,7 @@ func DeleteIssueLabel(ctx *context.APIContext) { // ReplaceIssueLabels replace labels for an issue func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { - // swagger:operation PUT /repos/{owner}/{repo}/issue/{index}/labels issue issueReplaceLabels + // swagger:operation PUT /repos/{owner}/{repo}/issues/{index}/labels issue issueReplaceLabels // --- // summary: Replace an issue's labels // consumes: @@ -264,7 +264,7 @@ func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) { // ClearIssueLabels delete all the labels for an issue func ClearIssueLabels(ctx *context.APIContext) { - // swagger:operation DELETE /repos/{owner}/{repo}/issue/{index}/labels issue issueClearLabels + // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/labels issue issueClearLabels // --- // summary: Remove all labels from an issue // produces: diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 3ea4b8d327b..78d96c647fe 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -211,26 +211,6 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption milestoneID = milestone.ID } - if len(form.Assignee) > 0 { - assigneeUser, err := models.GetUserByName(form.Assignee) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", form.Assignee)) - } else { - ctx.Error(500, "GetUserByName", err) - } - return - } - - assignee, err := repo.GetAssigneeByID(assigneeUser.ID) - if err != nil { - ctx.Error(500, "GetAssigneeByID", err) - return - } - - assigneeID = assignee.ID - } - patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch) if err != nil { ctx.Error(500, "GetPatch", err) @@ -266,7 +246,22 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption Type: models.PullRequestGitea, } - if err := models.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch); err != nil { + // Get all assignee IDs + assigneeIDs, err := models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err)) + } else { + ctx.Error(500, "AddAssigneeByName", err) + } + return + } + + if err := models.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch, assigneeIDs); err != nil { + if models.IsErrUserDoesNotHaveAccessToRepo(err) { + ctx.Error(400, "UserDoesNotHaveAccessToRepo", err) + return + } ctx.Error(500, "NewPullRequest", err) return } else if err := pr.PushToBaseRepo(); err != nil { @@ -335,6 +330,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) { issue.Content = form.Body } + // Update Deadline var deadlineUnix util.TimeStamp if form.Deadline != nil && !form.Deadline.IsZero() { deadlineUnix = util.TimeStamp(form.Deadline.Unix()) @@ -345,28 +341,27 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) { return } - if ctx.Repo.IsWriter() && len(form.Assignee) > 0 && - (issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(form.Assignee)) { - if len(form.Assignee) == 0 { - issue.AssigneeID = 0 - } else { - assignee, err := models.GetUserByName(form.Assignee) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", form.Assignee)) - } else { - ctx.Error(500, "GetUserByName", err) - } - return - } - issue.AssigneeID = assignee.ID - } + // Add/delete assignees - if err = models.UpdateIssueUserByAssignee(issue); err != nil { - ctx.Error(500, "UpdateIssueUserByAssignee", err) + // Deleting is done the Github way (quote from their api documentation): + // https://developer.github.com/v3/issues/#edit-an-issue + // "assignees" (array): Logins for Users to assign to this issue. + // Pass one or more user logins to replace the set of assignees on this Issue. + // Send an empty array ([]) to clear all assignees from the Issue. + + if ctx.Repo.IsWriter() && (form.Assignees != nil || len(form.Assignee) > 0) { + + err = models.UpdateAPIAssignee(issue, form.Assignee, form.Assignees, ctx.User) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", err)) + } else { + ctx.Error(500, "UpdateAPIAssignee", err) + } return } } + if ctx.Repo.IsWriter() && form.Milestone != 0 && issue.MilestoneID != form.Milestone { oldMilestoneID := issue.MilestoneID diff --git a/routers/install.go b/routers/install.go index 2a7ec93d211..84e506c70b4 100644 --- a/routers/install.go +++ b/routers/install.go @@ -112,6 +112,7 @@ func Install(ctx *context.Context) { form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp form.DisableRegistration = setting.Service.DisableRegistration + form.AllowOnlyExternalRegistration = setting.Service.AllowOnlyExternalRegistration form.EnableCaptcha = setting.Service.EnableCaptcha form.RequireSignInView = setting.Service.RequireSignInView form.DefaultKeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate @@ -304,6 +305,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) { cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(com.ToStr(form.EnableOpenIDSignIn)) cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(com.ToStr(form.EnableOpenIDSignUp)) cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration)) + cfg.Section("service").Key("ALLOW_ONLY_EXTERNAL_REGISTRATION").SetValue(com.ToStr(form.AllowOnlyExternalRegistration)) cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha)) cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView)) cfg.Section("service").Key("DEFAULT_KEEP_EMAIL_PRIVATE").SetValue(com.ToStr(form.DefaultKeepEmailPrivate)) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index a9100e56065..b955760642b 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -364,7 +364,7 @@ func NewIssue(ctx *context.Context) { } // ValidateRepoMetas check and returns repository's meta informations -func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, int64, int64) { +func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, []int64, int64) { var ( repo = ctx.Repo.Repository err error @@ -372,11 +372,11 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64 labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository) if ctx.Written() { - return nil, 0, 0 + return nil, nil, 0 } if !ctx.Repo.IsWriter() { - return nil, 0, 0 + return nil, nil, 0 } var labelIDs []int64 @@ -385,7 +385,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64 if len(form.LabelIDs) > 0 { labelIDs, err = base.StringsToInt64s(strings.Split(form.LabelIDs, ",")) if err != nil { - return nil, 0, 0 + return nil, nil, 0 } labelIDMark := base.Int64sToMap(labelIDs) @@ -407,23 +407,35 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64 ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID) if err != nil { ctx.ServerError("GetMilestoneByID", err) - return nil, 0, 0 + return nil, nil, 0 } ctx.Data["milestone_id"] = milestoneID } - // Check assignee. - assigneeID := form.AssigneeID - if assigneeID > 0 { - ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID) + // Check assignees + var assigneeIDs []int64 + if len(form.AssigneeIDs) > 0 { + assigneeIDs, err = base.StringsToInt64s(strings.Split(form.AssigneeIDs, ",")) if err != nil { - ctx.ServerError("GetAssigneeByID", err) - return nil, 0, 0 + return nil, nil, 0 + } + + // Check if the passed assignees actually exists and has write access to the repo + for _, aID := range assigneeIDs { + _, err = repo.GetUserIfHasWriteAccess(aID) + if err != nil { + ctx.ServerError("GetUserIfHasWriteAccess", err) + return nil, nil, 0 + } } - ctx.Data["assignee_id"] = assigneeID } - return labelIDs, milestoneID, assigneeID + // Keep the old assignee id thingy for compatibility reasons + if form.AssigneeID > 0 { + assigneeIDs = append(assigneeIDs, form.AssigneeID) + } + + return labelIDs, assigneeIDs, milestoneID } // NewIssuePost response for creating new issue @@ -440,7 +452,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { attachments []string ) - labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form) + labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form) if ctx.Written() { return } @@ -460,11 +472,14 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) { PosterID: ctx.User.ID, Poster: ctx.User, MilestoneID: milestoneID, - AssigneeID: assigneeID, Content: form.Content, Ref: form.Ref, } - if err := models.NewIssue(repo, issue, labelIDs, attachments); err != nil { + if err := models.NewIssue(repo, issue, labelIDs, assigneeIDs, attachments); err != nil { + if models.IsErrUserDoesNotHaveAccessToRepo(err) { + ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error()) + return + } ctx.ServerError("NewIssue", err) return } @@ -702,8 +717,8 @@ func ViewIssue(ctx *context.Context) { comment.Milestone = ghostMilestone } } else if comment.Type == models.CommentTypeAssignees { - if err = comment.LoadAssignees(); err != nil { - ctx.ServerError("LoadAssignees", err) + if err = comment.LoadAssigneeUser(); err != nil { + ctx.ServerError("LoadAssigneeUser", err) return } } else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview { @@ -917,13 +932,20 @@ func UpdateIssueAssignee(ctx *context.Context) { } assigneeID := ctx.QueryInt64("id") + action := ctx.Query("action") + for _, issue := range issues { - if issue.AssigneeID == assigneeID { - continue - } - if err := issue.ChangeAssignee(ctx.User, assigneeID); err != nil { - ctx.ServerError("ChangeAssignee", err) - return + switch action { + case "clear": + if err := models.DeleteNotPassedAssignee(issue, ctx.User, []*models.User{}); err != nil { + ctx.ServerError("ClearAssignees", err) + return + } + default: + if err := issue.ChangeAssignee(ctx.User, assigneeID); err != nil { + ctx.ServerError("ChangeAssignee", err) + return + } } } ctx.JSON(200, map[string]interface{}{ diff --git a/routers/repo/pull.go b/routers/repo/pull.go index c5e623234ca..6d665cd1721 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -785,7 +785,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) return } - labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form) + labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form) if ctx.Written() { return } @@ -821,7 +821,6 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) PosterID: ctx.User.ID, Poster: ctx.User, MilestoneID: milestoneID, - AssigneeID: assigneeID, IsPull: true, Content: form.Content, } @@ -838,7 +837,12 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) } // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt // instead of 500. - if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil { + + if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil { + if models.IsErrUserDoesNotHaveAccessToRepo(err) { + ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error()) + return + } ctx.ServerError("NewPullRequest", err) return } else if err := pullRequest.PushToBaseRepo(); err != nil { diff --git a/routers/repo/topic.go b/routers/repo/topic.go index 90ef0d189cd..2a43d53ff0b 100644 --- a/routers/repo/topic.go +++ b/routers/repo/topic.go @@ -21,7 +21,11 @@ func TopicPost(ctx *context.Context) { return } - topics := strings.Split(ctx.Query("topics"), ",") + var topics = make([]string, 0) + var topicsStr = strings.TrimSpace(ctx.Query("topics")) + if len(topicsStr) > 0 { + topics = strings.Split(topicsStr, ",") + } err := models.SaveTopics(ctx.Repo.Repository.ID, topics...) if err != nil { diff --git a/routers/user/auth.go b/routers/user/auth.go index 2a5cb8e4b29..c8e1ada0db1 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -741,7 +741,8 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - if setting.Service.DisableRegistration { + //Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true + if !setting.Service.ShowRegistrationButton { ctx.Error(403) return } diff --git a/snap/helpers/app.ini b/snap/helpers/app.ini new file mode 100644 index 00000000000..dd7fa3c88fc --- /dev/null +++ b/snap/helpers/app.ini @@ -0,0 +1,66 @@ +APP_NAME = Gitea: Go Git Service +RUN_USER = root +RUN_MODE = prod +CUSTOM_PATH = SNAP_DIR_DATA/custom + +[server] +DOMAIN = localhost +PROTOCOL = http +HTTP_PORT = 3001 +ROOT_URL = http://localhost:3001/ +DISABLE_SSH = false +SSH_PORT = 22 +STATIC_ROOT_PATH = SNAP_DIR_DATA/static +APP_DATA_PATH = SNAP_DIR_COMMON/data +SSH_ROOT = SNAP_DIR_COMMON/ssh +SSH_KEY_TEST_PATH = SNAP_DIR_DATA/sshkeytest + +[database] +DB_TYPE = sqlite3 +PATH = SNAP_DIR_COMMON/gitea.db + +[repository] +ROOT = SNAP_DIR_COMMON/repositories/data + +[repository.upload] +ENABLED = true +ALLOWED_TYPES = "image/jpeg|image/png" +FILE_MAX_SIZE = 10 +MAX_FILES = 5 +TEMP_PATH = SNAP_DIR_COMMON/repositories/tmp + +[release.attachment] +PATH = SNAP_DIR_COMMON/releases/attachments + +[smartypants] +ENABLED = true + +[indexer] +ISSUE_INDEXER_PATH = SNAP_DIR_COMMON/indexers/issues.bleve + + +[mailer] +ENABLED = false + +[service] +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +DISABLE_REGISTRATION = false +ENABLE_CAPTCHA = false +REQUIRE_SIGNIN_VIEW = false + +[picture] +AVATAR_UPLOAD_PATH = SNAP_DIR_COMMON/pictures/avatars +DISABLE_GRAVATAR = true +ENABLE_FEDERATED_AVATAR = false + +[attachment] +PATH = SNAP_DIR_COMMON/attachments + +[session] +PROVIDER = memory + +[log] +MODE = file +LEVEL = Trace +ROOT_PATH = SNAP_DIR_COMMON/log diff --git a/snap/helpers/configuration.sh b/snap/helpers/configuration.sh new file mode 100755 index 00000000000..34b7fc7af4d --- /dev/null +++ b/snap/helpers/configuration.sh @@ -0,0 +1,126 @@ +#!/bin/bash +if snapctl get gitea.snap.custom; then + cdir=$(snapctl get gitea.snap.custom) +else + cdir=$SNAP_COMMON +fi + +cfg="$cdir/conf/app.ini" +bak="$cdir/conf/app.ini.bak-$(date -Ins)" +basecfg="$SNAP/snap/helpers/app.ini" +smp="$SNAP/gitea/custom/conf/app.ini.sample" + +function toSnap() { +OIFS=$IFS +IFS=' +' + category="none" + src="$cfg" + [[ "$1" = "init" ]] && src="$smp" + [[ "$1" = "snap" ]] && src="$basecfg" + + for l in $(sed 's_;\([A-Z]*\)_\1_g' $src | grep -v -e '^;' -e '^$'); do + if echo $l | grep -q '^[[]'; then + category=$(CatToSnap "$l") + elif echo $l | grep -q '^[A-Z]'; then + option=$(OptToSnap "$l") + value=$(ValToSnap "$l") + if [[ $category = "none" ]]; then + snapctl set "$option=$value" + else + snapctl set "$category.$option=$value" + fi + fi + done +IFS=$OIFS +} + +function toIni() { +OIFS=$IFS +IFS=' +' + category="none"; option="none"; catUnset=true + src=$smp + [[ -f $cfg ]] && src="$cfg" + tmpIni="$cfg.tmp" + [[ -f $src ]] && cp "$src" "$tmpIni" + cp $tmpIni $bak + echo '' > $cfg + for l in $(grep -v -e '^;' -e '^$' $tmpIni); do + if echo $l | grep -q '^[[]'; then + category=$(CatToSnap "$l") + catUnset=true + elif echo $l | grep -q '^[A-Z]'; then + option=$(OptToSnap "$l") + if [[ $category = "none" ]]; then + value=$(snapctl get $option) + echo $(OptToIni "$option") = $value >> $cfg + else + value=$(snapctl get $category.$option) + if $catUnset; then + echo "" >> $cfg + echo "[$(CatToIni "$category")]" >> $cfg + catUnset=false + fi + echo $(OptToIni "$option") = $value >> $cfg + fi + fi + done; + IFS=$OIFS +} + +function CatToSnap { + ret=$(echo "$1" \ + | grep -oP '[A-Za-z0-9._]+' \ + | sed 's|\.|-|g' \ + | sed 's|_|99|g') + echo $ret +} +function OptToSnap { + ret=$(echo "$1" \ + | grep -oP '^[A-Z_]+' \ + | tr '[:upper:]' '[:lower:]' \ + | sed 's|_|-|g') + echo $ret +} +function ValToSnap { + ret=$(echo "$1" \ + | grep -oP '=.*$' \ + | sed 's_^= __g' \ + | sed 's_^=__g' \ + | sed "s|SNAP_DIR_DATA|$SDATA|g" \ + | sed "s|SNAP_DIR_COMMON|$SCOMMON|g" \ + | sed 's|{}||g') + echo $ret +} + +function CatToIni { + ret=$(echo "$1" \ + | sed 's|-|.|g' \ + | sed 's|\ |_|g' \ + | sed 's|99|_|g') + echo $ret +} +function OptToIni { + ret=$(echo "$1" \ + | tr '[:lower:]' '[:upper:]' \ + | sed 's|-|_|g') + echo $ret +} + +[[ "$1" = "configure" ]] \ + && toIni \ + && exit 0 + +[[ "$1" = "install" ]] \ + && echo "Initial Configuration..." \ + && mkdir -p $SNAP_COMMON/conf \ + && toSnap init \ + && toSnap snap \ + && toIni sample \ + && exit 0 + +[[ "$1" = "save" ]] \ + && echo "Saving current config..." \ + && toSnap \ + && exit 0 diff --git a/snap/helpers/simple_launcher.sh b/snap/helpers/simple_launcher.sh new file mode 100755 index 00000000000..8a12e3b8dd5 --- /dev/null +++ b/snap/helpers/simple_launcher.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if ! env | grep -q root; then + echo " + +----------------------------------------+ + | You are not running gitea as root. | + | This is required for the snap package. | + | Please re-run as root. | + +----------------------------------------+ +" + $SNAP/gitea/gitea --help + exit 1 +fi + +# Set usernames for gitea +export USERNAME=root +export USER=root + +export GITEA_WORK_DIR=$(snapctl get gitea.snap.workdir) +export GITEA_CUSTOM=$(snapctl get gitea.snap.custom) + +$SNAP/bin/gconfig save +cd $SNAP/gitea; ./gitea $@ diff --git a/snap/hooks/configure b/snap/hooks/configure new file mode 100755 index 00000000000..fd7bc3da180 --- /dev/null +++ b/snap/hooks/configure @@ -0,0 +1,3 @@ +#!/bin/bash + +$SNAP/bin/gconfig configure diff --git a/snap/hooks/install b/snap/hooks/install new file mode 100755 index 00000000000..dea6c268fbd --- /dev/null +++ b/snap/hooks/install @@ -0,0 +1,45 @@ +#!/bin/bash + +export SDATA=$(echo $SNAP_DATA | sed "s|$SNAP_REVISION|current|") +export SCOMMON="$SNAP_COMMON" +export isRoot=`true` +snapctl set gitea.snap.workdir="$SDATA/custom" +snapctl set gitea.snap.custom="$SCOMMON" + +function mkDirCommon(){ + for dir in $@; do + mkdir -p "$SCOMMON/$dir" + done +} + +function mkdirData(){ + for dir in $@; do + mkdir -p "$SDATA/$dir" + if [ -d $SNAP/$dir ]; then + cp -r --preserve=mode \ + $SNAP/$dir/* \ + $SNAP/$dir/.[a-zA-Z0-9-]* \ + $SDATA/$dir/ 2> $SCOMMON/log/snap-mkdirData.log + fi + done +} + +mkDirCommon pictures \ + repositories \ + attachments \ + data \ + log + +mkdirData certs \ + sshkeytest \ + custom/conf \ + static/templates \ + static/scripts \ + static/public + +[[ -f $SNAP_COMMON/conf/app.ini ]] || $SNAP/bin/gconfig install + +# Configure Git to use the right templates +mkdir -p $SDATA/git/ +cp -r --preserve=mode $SNAP/usr/share/git-core/templates $SDATA/git/ +$SNAP/usr/bin/git config --global init.templateDir $SDATA/git/templates/ diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 00000000000..7439f50f255 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,121 @@ +name: gitea +summary: Gitea - A painless self-hosted Git service +description: | + The goal of this project is to make the easiest, fastest, and most painless + way of setting up a self-hosted Git service. With Go, this can be done with + an independent binary distribution across ALL platforms that Go supports, + including Linux, Mac OS X, Windows and ARM. + +type: app +icon: public/img/gitea-lg.png +confinement: strict +grade: stable + +version: 'git' + +apps: + gitea: + command: bin/gitea + plugs: [network, network-bind] + web: + command: bin/gitea web + daemon: simple + plugs: [network, network-bind] + serv: + command: bin/gitea serv + plugs: [network, network-bind] + admin: + command: bin/gitea admin + plugs: [network, network-bind] + cert: + command: bin/gitea cert + hook: + command: bin/gitea hook + plugs: [network, network-bind] + dump: + command: bin/gitea dump + plugs: [home] + help: + command: bin/gitea --help + version: + command: bin/gitea --version + sqlite: + command: usr/bin/sqlite3 + +parts: + go: + source-tag: go1.8.3 + prime: + - -* + + gitea: + plugin: nil + source: . + source-type: git + after: [ go ] + stage-packages: [ git, sqlite3, openssh-client ] + build-packages: [ libpam0g-dev, libsqlite3-dev] + prepare: | + export PATH=$SNAPCRAFT_PART_INSTALL/../../go/install/bin:$PATH + export GOPATH=$SNAPCRAFT_PART_INSTALL/../go + export bld=$SNAPCRAFT_PART_INSTALL/../build + export src=$SNAPCRAFT_PART_INSTALL/../src + mkdir -p $GOPATH/src/code.gitea.io/gitea + cp -r $src/* $GOPATH/src/code.gitea.io/gitea + build: | + export PATH=$SNAPCRAFT_PART_INSTALL/../go/bin/:$SNAPCRAFT_PART_INSTALL/../../go/install/bin:$PATH + export GOPATH=$SNAPCRAFT_PART_INSTALL/../go + go get -u github.com/jteeuwen/go-bindata/... + cd $GOPATH/src/code.gitea.io/gitea + TAGS="bindata sqlite pam cert" make generate build + install: | + # Set Convenience Variables + src=$SNAPCRAFT_PART_INSTALL/../go/src/code.gitea.io/gitea + giteaBase=$SNAPCRAFT_PART_INSTALL/gitea + scurrent=/var/snap/$SNAPCRAFT_PROJECT_NAME/current + scommon=/var/snap/$SNAPCRAFT_PROJECT_NAME/common + # Copy build artifact and necessary files + mkdir -p $giteaBase/conf + # Workaround for gitea ignoring APP_DATA_PATH in app.ini after snap update. + ln -s $scurrent/custom $giteaBase/custom + ln -s $scommon/data $giteaBase/data + # Workaround for cmd/certs not knowing how to put files somewhere else + ln -s $scurrent/cert.pem $giteaBase/cert.pem + ln -s $scurrent/key.pem $giteaBase/key.pem + # Copy static content + mkdir -p $SNAPCRAFT_PART_INSTALL/static + cp $src/gitea $giteaBase/ + cp -r $src/LICENSE \ + $src/templates \ + $src/public \ + $src/scripts \ + $SNAPCRAFT_PART_INSTALL/static/ + cp -r $src/README.md \ + $src/LICENSE \ + $src/custom \ + $SNAPCRAFT_PART_INSTALL/ + prime: + - -etc + - -usr/lib/systemd + - -usr/lib/gcc + - -usr/lib/sasl2 + - -usr/lib/x86_64-linux-gnu/krb5 + - -usr/share/apport + - -usr/share/bash-completion + - -usr/share/doc + - -usr/share/git-core/contrib + - -usr/share/man + - -usr/share/upstart + - -var + + helpers: + plugin: dump + source: snap/helpers + organize: + simple_launcher.sh: bin/gitea + app.ini: gitea/snapApp.ini + configuration.sh: bin/gconfig + prime: + - bin/gitea + - bin/gconfig + - gitea/snapApp.ini diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 370325692ea..d8292a9e6bf 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -114,6 +114,8 @@
{{.i18n.Tr "admin.config.disable_register"}}
+
{{.i18n.Tr "admin.config.allow_only_external_registration"}}
+
{{.i18n.Tr "admin.config.show_registration_button"}}
{{.i18n.Tr "admin.config.enable_openid_signup"}}
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl index 16507df16ae..b8f4490c112 100644 --- a/templates/explore/repo_list.tmpl +++ b/templates/explore/repo_list.tmpl @@ -17,9 +17,13 @@ {{if .DescriptionHTML}}

{{.DescriptionHTML}}

{{end}} -
- {{range .Topics}}
{{.}}
{{end}} -
+ {{if .Topics }} +
+ {{range .Topics}} + {{if ne . "" }}
{{.}}
{{end}} + {{end}} +
+ {{end}}

{{$.i18n.Tr "org.repo_updated"}} {{TimeSinceUnix .UpdatedUnix $.i18n.Lang}}

{{else}} diff --git a/templates/install.tmpl b/templates/install.tmpl index bd79b3a068b..46439b4979b 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -200,6 +200,12 @@ +
+
+ + +
+
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index f4c0d0d163a..6d1d9edf8c2 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -48,7 +48,7 @@
- +
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index cbbd78d3c43..53ce411e1cc 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -118,15 +118,29 @@ {{else if eq .Type 9}}
- {{if gt .AssigneeID 0}}{{if eq .Poster.ID .AssigneeID}} - - {{.Poster.Name}} {{$.i18n.Tr "repo.issues.self_assign_at" $createdStr | Safe}} - {{else}} - - {{.Assignee.Name}} {{$.i18n.Tr "repo.issues.add_assignee_at" .Poster.Name $createdStr | Safe}} {{end}}{{else if gt .OldAssigneeID 0}} - - - {{.Poster.Name}} {{$.i18n.Tr "repo.issues.remove_assignee_at" $createdStr | Safe}} {{end}} + {{if gt .AssigneeID 0}} + {{if .RemovedAssignee}} + + + + + {{.Assignee.Name}} + {{$.i18n.Tr "repo.issues.remove_assignee_at" $createdStr | Safe}} + + {{else}} + + + + + {{.Assignee.Name}} + {{if eq .Poster.ID .AssigneeID}} + {{$.i18n.Tr "repo.issues.self_assign_at" $createdStr | Safe}} + {{else}} + {{$.i18n.Tr "repo.issues.add_assignee_at" .Poster.Name $createdStr | Safe}} + {{end}} + + {{end}} + {{end}}
{{else if eq .Type 10}}
diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 648533fca1c..f0e4f96cfa4 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -68,23 +68,40 @@
-