mirror of
https://github.com/louislam/dockge.git
synced 2024-11-27 21:24:02 +00:00
Merge branch 'master' into close-terminal
# Conflicts: # backend/terminal.ts
This commit is contained in:
commit
b6141b18f5
68 changed files with 3394 additions and 322 deletions
|
@ -92,6 +92,9 @@ module.exports = {
|
||||||
"one-var": [ "error", "never" ],
|
"one-var": [ "error", "never" ],
|
||||||
"max-statements-per-line": [ "error", { "max": 1 }],
|
"max-statements-per-line": [ "error", { "max": 1 }],
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": [ "warn", {
|
||||||
|
"args": "none"
|
||||||
|
}],
|
||||||
"prefer-const" : "off",
|
"prefer-const" : "off",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
72
.github/DISCUSSION_TEMPLATE/ask-for-help.yml
vendored
Normal file
72
.github/DISCUSSION_TEMPLATE/ask-for-help.yml
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
title: "❓ Ask for help"
|
||||||
|
labels: [help]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this bug has NOT been raised before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/dockge/discussions/categories/ask-for-help)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar issue"
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: "🛡️ Security Policy"
|
||||||
|
description: Please review the security policy before reporting security related issues/bugs.
|
||||||
|
options:
|
||||||
|
- label: I agree to have read this project [Security Policy](https://github.com/louislam/dockge/security/policy)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: steps-to-reproduce
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "📝 Describe your problem"
|
||||||
|
description: "Please walk us through it step by step."
|
||||||
|
placeholder: "Describe what are you asking for..."
|
||||||
|
- type: textarea
|
||||||
|
id: error-msg
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "📝 Error Message(s) or Log"
|
||||||
|
- type: input
|
||||||
|
id: dockge-version
|
||||||
|
attributes:
|
||||||
|
label: "🐻 Dockge Version"
|
||||||
|
description: "Which version of Dockge are you running? Please do NOT provide the docker tag such as latest or 1"
|
||||||
|
placeholder: "Ex. 1.10.0"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: operating-system
|
||||||
|
attributes:
|
||||||
|
label: "💻 Operating System and Arch"
|
||||||
|
description: "Which OS is your server/device running on? (For Replit, please do not report this bug)"
|
||||||
|
placeholder: "Ex. Ubuntu 20.04 x86"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: browser-vendor
|
||||||
|
attributes:
|
||||||
|
label: "🌐 Browser"
|
||||||
|
description: "Which browser are you running on? (For Replit, please do not report this bug)"
|
||||||
|
placeholder: "Ex. Google Chrome 95.0.4638.69"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: docker-version
|
||||||
|
attributes:
|
||||||
|
label: "🐋 Docker Version"
|
||||||
|
description: "If running with Docker, which version are you running?"
|
||||||
|
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: nodejs-version
|
||||||
|
attributes:
|
||||||
|
label: "🟩 NodeJS Version"
|
||||||
|
description: "If running with Node.js? which version are you running?"
|
||||||
|
placeholder: "Ex. 14.18.0"
|
||||||
|
validations:
|
||||||
|
required: false
|
55
.github/DISCUSSION_TEMPLATE/feature-request.yml
vendored
Normal file
55
.github/DISCUSSION_TEMPLATE/feature-request.yml
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
title: 🚀 Feature Request
|
||||||
|
labels: [feature-request]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this feature request has NOT been suggested before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/dockge/discussions/categories/feature-request)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar feature request"
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: feature-area
|
||||||
|
attributes:
|
||||||
|
label: "🏷️ Feature Request Type"
|
||||||
|
description: "What kind of feature request is this?"
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- API
|
||||||
|
- UI Feature
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: feature-description
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "🔖 Feature description"
|
||||||
|
description: "A clear and concise description of what the feature request is."
|
||||||
|
placeholder: "You should add ..."
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "✔️ Solution"
|
||||||
|
description: "A clear and concise description of what you want to happen."
|
||||||
|
placeholder: "In my use-case, ..."
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "❓ Alternatives"
|
||||||
|
description: "A clear and concise description of any alternative solutions or features you've considered."
|
||||||
|
placeholder: "I have considered ..."
|
||||||
|
- type: textarea
|
||||||
|
id: additional-context
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "📝 Additional Context"
|
||||||
|
description: "Add any other context or screenshots about the feature request here."
|
||||||
|
placeholder: "..."
|
14
.github/ISSUE_TEMPLATE/ask-for-help.yaml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/ask-for-help.yaml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: "❓ Ask for help"
|
||||||
|
description: "Please go to the Discussions tab to submit a Help Request"
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Please go to https://github.com/louislam/dockge/discussions/new?category=ask-for-help
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "Issues are for bug reports only"
|
||||||
|
options:
|
||||||
|
- label: "I understand"
|
||||||
|
required: true
|
99
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
99
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
name: "🐛 Bug Report"
|
||||||
|
description: "Submit a bug report to help us improve"
|
||||||
|
#title: "[Bug] "
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "⚠️ Please verify that this bug has NOT been reported before."
|
||||||
|
description: "Search in the issues sections by clicking [HERE](https://github.com/louislam/dockge/issues?q=)"
|
||||||
|
options:
|
||||||
|
- label: "I checked and didn't find similar issue"
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: "🛡️ Security Policy"
|
||||||
|
description: Please review the security policy before reporting security related issues/bugs.
|
||||||
|
options:
|
||||||
|
- label: I agree to have read this project [Security Policy](https://github.com/louislam/dockge/security/policy)
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
attributes:
|
||||||
|
label: "Description"
|
||||||
|
description: "You could also upload screenshots"
|
||||||
|
- type: textarea
|
||||||
|
id: steps-to-reproduce
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "👟 Reproduction steps"
|
||||||
|
description: "How do you trigger this bug? Please walk us through it step by step."
|
||||||
|
placeholder: "..."
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "👀 Expected behavior"
|
||||||
|
description: "What did you think would happen?"
|
||||||
|
placeholder: "..."
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
attributes:
|
||||||
|
label: "😓 Actual Behavior"
|
||||||
|
description: "What actually happen?"
|
||||||
|
placeholder: "..."
|
||||||
|
- type: input
|
||||||
|
id: dockge-version
|
||||||
|
attributes:
|
||||||
|
label: "Dockge Version"
|
||||||
|
description: "Which version of Dockge are you running? Please do NOT provide the docker tag such as latest or 1"
|
||||||
|
placeholder: "Ex. 1.1.1"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: operating-system
|
||||||
|
attributes:
|
||||||
|
label: "💻 Operating System and Arch"
|
||||||
|
description: "Which OS is your server/device running on?"
|
||||||
|
placeholder: "Ex. Ubuntu 20.04 x64 "
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: browser-vendor
|
||||||
|
attributes:
|
||||||
|
label: "🌐 Browser"
|
||||||
|
description: "Which browser are you running on?"
|
||||||
|
placeholder: "Ex. Google Chrome 95.0.4638.69"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: docker-version
|
||||||
|
attributes:
|
||||||
|
label: "🐋 Docker Version"
|
||||||
|
description: "If running with Docker, which version are you running?"
|
||||||
|
placeholder: "Ex. Docker 20.10.9 / K8S / Podman"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
id: nodejs-version
|
||||||
|
attributes:
|
||||||
|
label: "🟩 NodeJS Version"
|
||||||
|
description: "If running with Node.js? which version are you running?"
|
||||||
|
placeholder: "Ex. 14.18.0"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: "📝 Relevant log output"
|
||||||
|
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: false
|
14
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: 🚀 Feature Request
|
||||||
|
description: "Please go to the Discussions tab to submit a Feature Request"
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Please go to https://github.com/louislam/dockge/discussions/new?category=feature-request
|
||||||
|
- type: checkboxes
|
||||||
|
id: no-duplicate-issues
|
||||||
|
attributes:
|
||||||
|
label: "Issues are for bug reports only"
|
||||||
|
options:
|
||||||
|
- label: "I understand"
|
||||||
|
required: true
|
19
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/security.md
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
name: "Security Issue"
|
||||||
|
about: "Just for alerting @louislam, do not provide any details here"
|
||||||
|
title: "Security Issue"
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- security
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
DO NOT PROVIDE ANY DETAILS HERE. Please privately report to https://github.com/louislam/dockge/security/advisories/new.
|
||||||
|
|
||||||
|
|
||||||
|
Why need this issue? It is because GitHub Advisory do not send a notification to @louislam, it is a workaround to do so.
|
||||||
|
|
||||||
|
Your GitHub Advisory URL:
|
||||||
|
|
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
34
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
⚠️⚠️⚠️ Since we do not accept all types of pull requests and do not want to waste your time. Please be sure that you have read pull request rules:
|
||||||
|
https://github.com/louislam/dockge/blob/master/CONTRIBUTING.md
|
||||||
|
|
||||||
|
Tick the checkbox if you understand [x]:
|
||||||
|
- [ ] I have read and understand the pull request rules.
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
Fixes #(issue)
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
Please delete any options that are not relevant.
|
||||||
|
|
||||||
|
- Bug fix (non-breaking change which fixes an issue)
|
||||||
|
- User interface (UI)
|
||||||
|
- New feature (non-breaking change which adds functionality)
|
||||||
|
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||||
|
- Other
|
||||||
|
- This change requires a documentation update
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] My code follows the style guidelines of this project
|
||||||
|
- [ ] I ran ESLint and other linters for modified files
|
||||||
|
- [ ] I have performed a self-review of my own code and tested it
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
(including JSDoc for methods)
|
||||||
|
- [ ] My changes generate no new warnings
|
||||||
|
- [ ] My code needed automated testing. I have added them (this is optional task)
|
||||||
|
|
||||||
|
## Screenshots (if any)
|
||||||
|
|
||||||
|
Please do not use any external image service. Instead, just paste in or drag and drop the image here, and it will be uploaded automatically.
|
1
.github/config/exclude.txt
vendored
Normal file
1
.github/config/exclude.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# This is a .gitignore style file for 'GrantBirki/json-yaml-validate' Action workflow
|
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
|
@ -15,12 +15,15 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
node: [18.x, 20.x] # Can be changed
|
node: [20.x] # Can be changed
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- run: git config --global core.autocrlf false # Mainly for Windows
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
@ -48,5 +51,13 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: pnpm run lint
|
||||||
|
|
||||||
|
- name: Check Typescript
|
||||||
|
run: pnpm run check-ts
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: pnpm run build:frontend
|
||||||
# more things can be add later like tests etc..
|
# more things can be add later like tests etc..
|
||||||
|
|
||||||
|
|
42
.github/workflows/close-incorrect-issue.yml
vendored
Normal file
42
.github/workflows/close-incorrect-issue.yml
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
name: Close Incorrect Issue
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
close-incorrect-issue:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
node-version: [16]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
name: Install pnpm
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Get pnpm store directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
name: Setup pnpm cache
|
||||||
|
with:
|
||||||
|
path: ${{ env.STORE_PATH }}
|
||||||
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pnpm-store-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Close Incorrect Issue
|
||||||
|
run: node extra/close-incorrect-issue.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.issue.number }} ${{ github.event.issue.user.login }}
|
27
.github/workflows/json-yaml-validate.yml
vendored
Normal file
27
.github/workflows/json-yaml-validate.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
name: json-yaml-validate
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- 2.0.X
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write # enable write permissions for pull request comments
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
json-yaml-validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: json-yaml-validate
|
||||||
|
id: json-yaml-validate
|
||||||
|
uses: GrantBirki/json-yaml-validate@v1.3.0
|
||||||
|
with:
|
||||||
|
comment: "false" # enable comment mode
|
||||||
|
exclude_file: ".github/config/exclude.txt" # gitignore style file for exclusions
|
139
CONTRIBUTING.md
Normal file
139
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
## Can I create a pull request for Dockge?
|
||||||
|
|
||||||
|
Yes or no, it depends on what you will try to do. Since I don't want to waste your time, be sure to **create open a discussion, so we can have a discussion first**. Especially for a large pull request or you don't know if it will be merged or not.
|
||||||
|
|
||||||
|
Here are some references:
|
||||||
|
|
||||||
|
### ✅ Usually accepted:
|
||||||
|
- Bug fix
|
||||||
|
- Security fix
|
||||||
|
- Translation
|
||||||
|
|
||||||
|
### ⚠️ Discussion required:
|
||||||
|
- Large pull requests
|
||||||
|
- New features
|
||||||
|
|
||||||
|
### ❌ Won't be merged:
|
||||||
|
- Do not pass the auto-test
|
||||||
|
- Any breaking changes
|
||||||
|
- Duplicated pull requests
|
||||||
|
- Buggy
|
||||||
|
- UI/UX is not close to Dockge
|
||||||
|
- Modifications or deletions of existing logic without a valid reason.
|
||||||
|
- Adding functions that is completely out of scope
|
||||||
|
- Converting existing code into other programming languages
|
||||||
|
- Unnecessarily large code changes that are hard to review and cause conflicts with other PRs.
|
||||||
|
|
||||||
|
The above cases may not cover all possible situations.
|
||||||
|
|
||||||
|
I (@louislam) have the final say. If your pull request does not meet my expectations, I will reject it, no matter how much time you spend on it. Therefore, it is essential to have a discussion beforehand.
|
||||||
|
|
||||||
|
I will assign your pull request to a [milestone](https://github.com/louislam/dockge/milestones), if I plan to review and merge it.
|
||||||
|
|
||||||
|
Also, please don't rush or ask for an ETA, because I have to understand the pull request, make sure it is no breaking changes and stick to my vision of this project, especially for large pull requests.
|
||||||
|
|
||||||
|
## Project Styles
|
||||||
|
|
||||||
|
I personally do not like something that requires so many configurations before you can finally start the app.
|
||||||
|
|
||||||
|
- Settings should be configurable in the frontend. Environment variables are discouraged, unless it is related to startup such as `DOCKGE_STACKS_DIR`
|
||||||
|
- Easy to use
|
||||||
|
- The web UI styling should be consistent and nice
|
||||||
|
- No native build dependency
|
||||||
|
|
||||||
|
## Coding Styles
|
||||||
|
|
||||||
|
- 4 spaces indentation
|
||||||
|
- Follow `.editorconfig`
|
||||||
|
- Follow ESLint
|
||||||
|
- Methods and functions should be documented with JSDoc
|
||||||
|
|
||||||
|
## Name Conventions
|
||||||
|
|
||||||
|
- Javascript/Typescript: camelCaseType
|
||||||
|
- SQLite: snake_case (Underscore)
|
||||||
|
- CSS/SCSS: kebab-case (Dash)
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
- [`Node.js`](https://nodejs.org/) >= 20
|
||||||
|
- [`pnpm`](https://pnpm.io/)
|
||||||
|
- [`git`](https://git-scm.com/)
|
||||||
|
- IDE that supports [`ESLint`](https://eslint.org/) and EditorConfig (I am using [`IntelliJ IDEA`](https://www.jetbrains.com/idea/))
|
||||||
|
- A SQLite GUI tool (f.ex. [`SQLite Expert Personal`](https://www.sqliteexpert.com/download.html) or [`DBeaver Community`](https://dbeaver.io/download/))
|
||||||
|
|
||||||
|
## Install Dependencies for Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dev Server
|
||||||
|
|
||||||
|
```
|
||||||
|
pnpm run dev:frontend
|
||||||
|
pnpm run dev:backend
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backend Dev Server
|
||||||
|
|
||||||
|
It binds to `0.0.0.0:5001` by default.
|
||||||
|
|
||||||
|
It is mainly a socket.io app + express.js.
|
||||||
|
|
||||||
|
## Frontend Dev Server
|
||||||
|
|
||||||
|
It binds to `0.0.0.0:5000` by default. The frontend dev server is used for development only.
|
||||||
|
|
||||||
|
For production, it is not used. It will be compiled to `frontend-dist` directory instead.
|
||||||
|
|
||||||
|
You can use Vue.js devtools Chrome extension for debugging.
|
||||||
|
|
||||||
|
### Build the frontend
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Migration
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
Both frontend and backend share the same package.json. However, the frontend dependencies are eventually not used in the production environment, because it is usually also baked into dist files. So:
|
||||||
|
|
||||||
|
- Frontend dependencies = "devDependencies"
|
||||||
|
- Examples: vue, chart.js
|
||||||
|
- Backend dependencies = "dependencies"
|
||||||
|
- Examples: socket.io, sqlite3
|
||||||
|
- Development dependencies = "devDependencies"
|
||||||
|
- Examples: eslint, sass
|
||||||
|
|
||||||
|
### Update Dependencies
|
||||||
|
|
||||||
|
Should only be done by the maintainer.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm update
|
||||||
|
````
|
||||||
|
|
||||||
|
It should update the patch release version only.
|
||||||
|
|
||||||
|
Patch release = the third digit ([Semantic Versioning](https://semver.org/))
|
||||||
|
|
||||||
|
If for security / bug / other reasons, a library must be updated, breaking changes need to be checked by the person proposing the change.
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
Please add **all** the strings which are translatable to `src/lang/en.json` (If translation keys are omitted, they can not be translated).
|
||||||
|
|
||||||
|
**Don't include any other languages in your initial Pull-Request** (even if this is your mother tongue), to avoid merge-conflicts between weblate and `master`.
|
||||||
|
The translations can then (after merging a PR into `master`) be translated by awesome people donating their language skills.
|
||||||
|
|
||||||
|
If you want to help by translating Uptime Kuma into your language, please visit the [instructions on how to translate using weblate](https://github.com/louislam/uptime-kuma/blob/master/src/lang/README.md).
|
||||||
|
|
||||||
|
## Spelling & Grammar
|
||||||
|
|
||||||
|
Feel free to correct the grammar in the documentation or code.
|
||||||
|
My mother language is not English and my grammar is not that great.
|
30
README.md
30
README.md
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.
|
A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.
|
||||||
|
|
||||||
![GitHub Repo stars](https://img.shields.io/github/stars/louislam/dockge?logo=github) ![GitHub issues](https://img.shields.io/github/issues/louislam/dockge?logo=github) ![GitHub pull requests](https://img.shields.io/github/issues-pr/louislam/dockge?logo=github) ![Docker Pulls](https://img.shields.io/docker/pulls/louislam/dockge?logo=docker) ![Docker Image Version (latest semver)](https://img.shields.io/docker/v/louislam/dockge?logo=docker) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/louislam/dockge/master?logo=github) ![GitHub](https://img.shields.io/github/license/louislam/dockge?logo=github)
|
![GitHub Repo stars](https://img.shields.io/github/stars/louislam/dockge?logo=github) ![GitHub issues](https://img.shields.io/github/issues/louislam/dockge?logo=github) ![GitHub pull requests](https://img.shields.io/github/issues-pr/louislam/dockge?logo=github) ![Docker Pulls](https://img.shields.io/docker/pulls/louislam/dockge?logo=docker) ![Docker Image Version (latest semver)](https://img.shields.io/docker/v/louislam/dockge/latest?label=docker%20image%20ver.) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/louislam/dockge/master?logo=github) ![GitHub](https://img.shields.io/github/license/louislam/dockge?logo=github)
|
||||||
|
|
||||||
<img src="https://github.com/louislam/dockge/assets/1336778/26a583e1-ecb1-4a8d-aedf-76157d714ad7" width="900" alt="" />
|
<img src="https://github.com/louislam/dockge/assets/1336778/26a583e1-ecb1-4a8d-aedf-76157d714ad7" width="900" alt="" />
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ View Video: https://youtu.be/AWAlOQeNpgU?t=48
|
||||||
- Reactive
|
- Reactive
|
||||||
- Everything is just responsive. Progress (Pull/Up/Down) and terminal output are in real-time
|
- Everything is just responsive. Progress (Pull/Up/Down) and terminal output are in real-time
|
||||||
- Easy-to-use & fancy UI
|
- Easy-to-use & fancy UI
|
||||||
- If you love Uptime Kuma's UI/UX, you will love this too
|
- If you love Uptime Kuma's UI/UX, you will love this one too
|
||||||
- Convert `docker run ...` commands into `compose.yaml`
|
- Convert `docker run ...` commands into `compose.yaml`
|
||||||
- File based structure
|
- File based structure
|
||||||
- Dockge won't kidnap your compose files, they stored on your drive as usual. You can interact with them using normal `docker compose` commands
|
- Dockge won't kidnap your compose files, they are stored on your drive as usual. You can interact with them using normal `docker compose` commands
|
||||||
<img src="https://github.com/louislam/dockge/assets/1336778/cc071864-592e-4909-b73a-343a57494002" width=300 />
|
<img src="https://github.com/louislam/dockge/assets/1336778/cc071864-592e-4909-b73a-343a57494002" width=300 />
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ cd /opt/dockge
|
||||||
# Download the compose.yaml
|
# Download the compose.yaml
|
||||||
curl https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml --output compose.yaml
|
curl https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml --output compose.yaml
|
||||||
|
|
||||||
# Start Server
|
# Start the Server
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
# If you are using docker-compose V1 or Podman
|
# If you are using docker-compose V1 or Podman
|
||||||
|
@ -75,7 +75,7 @@ services:
|
||||||
image: louislam/dockge:1
|
image: louislam/dockge:1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
# Host Port:Container Port
|
# Host Port : Container Port
|
||||||
- 5001:5001
|
- 5001:5001
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
@ -86,8 +86,8 @@ services:
|
||||||
|
|
||||||
# Your stacks directory in the host (The paths inside container must be the same as the host)
|
# Your stacks directory in the host (The paths inside container must be the same as the host)
|
||||||
# ⚠️⚠️ If you did it wrong, your data could end up be written into a wrong path.
|
# ⚠️⚠️ If you did it wrong, your data could end up be written into a wrong path.
|
||||||
# ✔️✔️✔️✔️ CORRECT EXAMPLE: - /my-stacks:/my-stacks (Both paths match)
|
# ✔️✔️✔️✔️ CORRECT: - /my-stacks:/my-stacks (Both paths match)
|
||||||
# ❌❌❌❌ WRONG EXAMPLE: - /docker:/my-stacks (Both paths do not match)
|
# ❌❌❌❌ WRONG: - /docker:/my-stacks (Both paths do not match)
|
||||||
- /opt/stacks:/opt/stacks
|
- /opt/stacks:/opt/stacks
|
||||||
environment:
|
environment:
|
||||||
# Tell Dockge where is your stacks directory
|
# Tell Dockge where is your stacks directory
|
||||||
|
@ -117,9 +117,9 @@ docker compose up -d
|
||||||
## Motivations
|
## Motivations
|
||||||
|
|
||||||
- I have been using Portainer for some time, but for the stack management, I am sometimes not satisfied with it. For example, sometimes when I try to deploy a stack, the loading icon keeps spinning for a few minutes without progress. And sometimes error messages are not clear.
|
- I have been using Portainer for some time, but for the stack management, I am sometimes not satisfied with it. For example, sometimes when I try to deploy a stack, the loading icon keeps spinning for a few minutes without progress. And sometimes error messages are not clear.
|
||||||
- Try to develop with ES Module + TypeScript (Originally, I planned to use Deno or Bun.js, but they do not support for arm64, so I stepped back to Node.js)
|
- Try to develop with ES Module + TypeScript (Originally, I planned to use Deno or Bun.js, but they don't have support for arm64, so I stepped back to Node.js)
|
||||||
|
|
||||||
If you love this project, please consider giving this project a ⭐.
|
If you love this project, please consider giving it a ⭐.
|
||||||
|
|
||||||
|
|
||||||
## 🗣️
|
## 🗣️
|
||||||
|
@ -130,17 +130,21 @@ https://github.com/louislam/dockge/issues
|
||||||
### Ask for Help / Discussions
|
### Ask for Help / Discussions
|
||||||
https://github.com/louislam/dockge/discussions
|
https://github.com/louislam/dockge/discussions
|
||||||
|
|
||||||
|
## Translation
|
||||||
|
|
||||||
|
If you want to translate Dockge into your language, please read [Translation Guide](https://github.com/louislam/dockge/blob/master/frontend/src/lang/README.md)
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
#### "Dockge"?
|
#### "Dockge"?
|
||||||
|
|
||||||
"Dockge" is a coinage word which is created by myself. I hope it sounds like `Dodge`.
|
"Dockge" is a coinage word which is created by myself. I hope it sounds like `Dodge`.
|
||||||
|
|
||||||
The naming idea was coming from Twitch emotes like `sadge`, `bedge` or `wokege`. They are all ending with `-ge`.
|
The naming idea came from Twitch emotes like `sadge`, `bedge` or `wokege`. They all end in `-ge`.
|
||||||
|
|
||||||
#### Can I manage a single container without `compose.yaml`?
|
#### Can I manage a single container without `compose.yaml`?
|
||||||
|
|
||||||
The main objective of Dockge is that try to use docker `compose.yaml` for everything. If you want to manage a single container, you can just use Portainer or Docker CLI.
|
The main objective of Dockge is to try to use the docker `compose.yaml` for everything. If you want to manage a single container, you can just use Portainer or Docker CLI.
|
||||||
|
|
||||||
#### Can I manage existing stacks?
|
#### Can I manage existing stacks?
|
||||||
|
|
||||||
|
@ -164,6 +168,4 @@ Yes, you can. However, you need to move your compose file into the stacks direct
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
|
|
||||||
Dockge is built on top of [Compose V2](https://docs.docker.com/compose/migrate/). `compose.yaml` is also known as `docker-compose.yml`.
|
Dockge is built on top of [Compose V2](https://docs.docker.com/compose/migrate/). `compose.yaml` also known as `docker-compose.yml`.
|
||||||
|
|
||||||
|
|
||||||
|
|
12
SECURITY.md
Normal file
12
SECURITY.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
1. Please report security issues to https://github.com/louislam/dockge/security/advisories/new.
|
||||||
|
1. Please also create an empty security issue to alert me, as GitHub Advisories do not send a notification, I probably will miss it without this. https://github.com/louislam/dockge/issues/new?assignees=&labels=help&template=security.md
|
||||||
|
|
||||||
|
Do not use the public issue tracker or discuss it in public as it will cause more damage.
|
||||||
|
|
||||||
|
## Do you accept other 3rd-party bug bounty platforms?
|
||||||
|
|
||||||
|
At this moment, I DO NOT accept other bug bounty platforms, because I am not familiar with these platforms and someone has tried to send a phishing link to me by doing this already. To minimize my own risk, please report through GitHub Advisories only. I will ignore all 3rd-party bug bounty platforms emails.
|
|
@ -5,6 +5,7 @@ import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import knex from "knex";
|
import knex from "knex";
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import Dialect from "knex/lib/dialects/sqlite3/index.js";
|
import Dialect from "knex/lib/dialects/sqlite3/index.js";
|
||||||
|
|
||||||
import sqlite from "@louislam/sqlite3";
|
import sqlite from "@louislam/sqlite3";
|
||||||
|
@ -12,6 +13,11 @@ import { sleep } from "./util-common";
|
||||||
|
|
||||||
interface DBConfig {
|
interface DBConfig {
|
||||||
type?: "sqlite" | "mysql";
|
type?: "sqlite" | "mysql";
|
||||||
|
hostname?: string;
|
||||||
|
port?: string;
|
||||||
|
database?: string;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Database {
|
export class Database {
|
||||||
|
@ -19,7 +25,7 @@ export class Database {
|
||||||
* SQLite file path (Default: ./data/dockge.db)
|
* SQLite file path (Default: ./data/dockge.db)
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
static sqlitePath;
|
static sqlitePath : string;
|
||||||
|
|
||||||
static noReject = true;
|
static noReject = true;
|
||||||
|
|
||||||
|
@ -51,7 +57,7 @@ export class Database {
|
||||||
* @typedef {string|undefined} envString
|
* @typedef {string|undefined} envString
|
||||||
* @returns {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} Database config
|
* @returns {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} Database config
|
||||||
*/
|
*/
|
||||||
static readDBConfig() {
|
static readDBConfig() : DBConfig {
|
||||||
const dbConfigString = fs.readFileSync(path.join(this.server.config.dataDir, "db-config.json")).toString("utf-8");
|
const dbConfigString = fs.readFileSync(path.join(this.server.config.dataDir, "db-config.json")).toString("utf-8");
|
||||||
const dbConfig = JSON.parse(dbConfigString);
|
const dbConfig = JSON.parse(dbConfigString);
|
||||||
|
|
||||||
|
@ -67,10 +73,10 @@ export class Database {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {string|undefined} envString
|
* @typedef {string|undefined} envString
|
||||||
* @param {{type: "sqlite"} | {type:envString, hostname:envString, port:envString, database:envString, username:envString, password:envString}} dbConfig the database configuration that should be written
|
* @param dbConfig the database configuration that should be written
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
static writeDBConfig(dbConfig) {
|
static writeDBConfig(dbConfig : DBConfig) {
|
||||||
fs.writeFileSync(path.join(this.server.config.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4));
|
fs.writeFileSync(path.join(this.server.config.dataDir, "db-config.json"), JSON.stringify(dbConfig, null, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,14 +86,17 @@ export class Database {
|
||||||
* @param {boolean} noLog Should logs not be output?
|
* @param {boolean} noLog Should logs not be output?
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async connect(autoloadModels = true, noLog = false) {
|
static async connect(autoloadModels = true) {
|
||||||
const acquireConnectionTimeout = 120 * 1000;
|
const acquireConnectionTimeout = 120 * 1000;
|
||||||
let dbConfig;
|
let dbConfig : DBConfig;
|
||||||
try {
|
try {
|
||||||
dbConfig = this.readDBConfig();
|
dbConfig = this.readDBConfig();
|
||||||
Database.dbConfig = dbConfig;
|
Database.dbConfig = dbConfig;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err instanceof Error) {
|
||||||
log.warn("db", err.message);
|
log.warn("db", err.message);
|
||||||
|
}
|
||||||
|
|
||||||
dbConfig = {
|
dbConfig = {
|
||||||
type: "sqlite",
|
type: "sqlite",
|
||||||
};
|
};
|
||||||
|
@ -176,6 +185,7 @@ export class Database {
|
||||||
directory: Database.knexMigrationsPath,
|
directory: Database.knexMigrationsPath,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
// Allow missing patch files for downgrade or testing pr.
|
// Allow missing patch files for downgrade or testing pr.
|
||||||
if (e.message.includes("the following files are missing:")) {
|
if (e.message.includes("the following files are missing:")) {
|
||||||
log.warn("db", e.message);
|
log.warn("db", e.message);
|
||||||
|
@ -186,6 +196,7 @@ export class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special handle, because tarn.js throw a promise reject that cannot be caught
|
* Special handle, because tarn.js throw a promise reject that cannot be caught
|
||||||
|
|
|
@ -61,7 +61,7 @@ export class DockgeServer {
|
||||||
*/
|
*/
|
||||||
needSetup = false;
|
needSetup = false;
|
||||||
|
|
||||||
jwtSecret? : string;
|
jwtSecret : string = "";
|
||||||
|
|
||||||
stacksDir : string = "";
|
stacksDir : string = "";
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ export class DockgeServer {
|
||||||
this.config.sslKey = args.sslKey || process.env.DOCKGE_SSL_KEY || undefined;
|
this.config.sslKey = args.sslKey || process.env.DOCKGE_SSL_KEY || undefined;
|
||||||
this.config.sslCert = args.sslCert || process.env.DOCKGE_SSL_CERT || undefined;
|
this.config.sslCert = args.sslCert || process.env.DOCKGE_SSL_CERT || undefined;
|
||||||
this.config.sslKeyPassphrase = args.sslKeyPassphrase || process.env.DOCKGE_SSL_KEY_PASSPHRASE || undefined;
|
this.config.sslKeyPassphrase = args.sslKeyPassphrase || process.env.DOCKGE_SSL_KEY_PASSPHRASE || undefined;
|
||||||
this.config.port = args.port || parseInt(process.env.DOCKGE_PORT) || 5001;
|
this.config.port = args.port || Number(process.env.DOCKGE_PORT) || 5001;
|
||||||
this.config.hostname = args.hostname || process.env.DOCKGE_HOSTNAME || undefined;
|
this.config.hostname = args.hostname || process.env.DOCKGE_HOSTNAME || undefined;
|
||||||
this.config.dataDir = args.dataDir || process.env.DOCKGE_DATA_DIR || "./data/";
|
this.config.dataDir = args.dataDir || process.env.DOCKGE_DATA_DIR || "./data/";
|
||||||
this.config.stacksDir = args.stacksDir || process.env.DOCKGE_STACKS_DIR || defaultStacksDir;
|
this.config.stacksDir = args.stacksDir || process.env.DOCKGE_STACKS_DIR || defaultStacksDir;
|
||||||
|
@ -219,7 +219,7 @@ export class DockgeServer {
|
||||||
log.debug("auth", "check auto login");
|
log.debug("auth", "check auto login");
|
||||||
if (await Settings.get("disableAuth")) {
|
if (await Settings.get("disableAuth")) {
|
||||||
log.info("auth", "Disabled Auth: auto login to admin");
|
log.info("auth", "Disabled Auth: auto login to admin");
|
||||||
this.afterLogin(socket as DockgeSocket, await R.findOne("user"));
|
this.afterLogin(socket as DockgeSocket, await R.findOne("user") as User);
|
||||||
socket.emit("autoLogin");
|
socket.emit("autoLogin");
|
||||||
} else {
|
} else {
|
||||||
log.debug("auth", "need auth");
|
log.debug("auth", "need auth");
|
||||||
|
@ -259,7 +259,9 @@ export class DockgeServer {
|
||||||
try {
|
try {
|
||||||
await Database.init(this);
|
await Database.init(this);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
log.error("server", "Failed to prepare your database: " + e.message);
|
log.error("server", "Failed to prepare your database: " + e.message);
|
||||||
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +291,7 @@ export class DockgeServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen
|
// Listen
|
||||||
this.httpServer.listen(5001, this.config.hostname, () => {
|
this.httpServer.listen(this.config.port, this.config.hostname, () => {
|
||||||
if (this.config.hostname) {
|
if (this.config.hostname) {
|
||||||
log.info( "server", `Listening on ${this.config.hostname}:${this.config.port}`);
|
log.info( "server", `Listening on ${this.config.hostname}:${this.config.port}`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,7 +299,7 @@ export class DockgeServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run every 5 seconds
|
// Run every 5 seconds
|
||||||
const job = Cron("*/2 * * * * *", {
|
Cron("*/2 * * * * *", {
|
||||||
protect: true, // Enabled over-run protection.
|
protect: true, // Enabled over-run protection.
|
||||||
}, () => {
|
}, () => {
|
||||||
log.debug("server", "Cron job running");
|
log.debug("server", "Cron job running");
|
||||||
|
@ -382,8 +384,10 @@ export class DockgeServer {
|
||||||
return process.env.TZ;
|
return process.env.TZ;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
log.warn("timezone", e.message + " in process.env.TZ");
|
log.warn("timezone", e.message + " in process.env.TZ");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const timezone = await Settings.get("serverTimezone");
|
const timezone = await Settings.get("serverTimezone");
|
||||||
|
|
||||||
|
@ -395,8 +399,10 @@ export class DockgeServer {
|
||||||
return timezone;
|
return timezone;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
log.warn("timezone", e.message + " in settings");
|
log.warn("timezone", e.message + " in settings");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Guess
|
// Guess
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -103,6 +103,10 @@ class Logger {
|
||||||
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
|
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
|
||||||
*/
|
*/
|
||||||
log(module: string, msg: unknown, level: string) {
|
log(module: string, msg: unknown, level: string) {
|
||||||
|
if (level === "DEBUG" && !isDev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function generatePasswordHash(password : string) {
|
||||||
* @param {string} hash Hash to verify against
|
* @param {string} hash Hash to verify against
|
||||||
* @returns {boolean} Does the password match the hash?
|
* @returns {boolean} Does the password match the hash?
|
||||||
*/
|
*/
|
||||||
export function verifyPassword(password, hash) {
|
export function verifyPassword(password : string, hash : string) {
|
||||||
return bcrypt.compareSync(password, hash);
|
return bcrypt.compareSync(password, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export const SHAKE256_LENGTH = 16;
|
||||||
* @param {number} len Output length of the hash
|
* @param {number} len Output length of the hash
|
||||||
* @returns {string} The hashed data in hex format
|
* @returns {string} The hashed data in hex format
|
||||||
*/
|
*/
|
||||||
export function shake256(data, len) {
|
export function shake256(data : string, len : number) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
// "limit" is bugged in Typescript, use "limiter-es6-compat" instead
|
// "limit" is bugged in Typescript, use "limiter-es6-compat" instead
|
||||||
// See https://github.com/jhurliman/node-rate-limiter/issues/80
|
// See https://github.com/jhurliman/node-rate-limiter/issues/80
|
||||||
import { RateLimiter } from "limiter-es6-compat";
|
import { RateLimiter, RateLimiterOpts } from "limiter-es6-compat";
|
||||||
import { log } from "./log";
|
import { log } from "./log";
|
||||||
|
|
||||||
|
export interface KumaRateLimiterOpts extends RateLimiterOpts {
|
||||||
|
errorMessage : string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type KumaRateLimiterCallback = (err : object) => void;
|
||||||
|
|
||||||
class KumaRateLimiter {
|
class KumaRateLimiter {
|
||||||
|
|
||||||
errorMessage : string;
|
errorMessage : string;
|
||||||
|
@ -11,7 +17,7 @@ class KumaRateLimiter {
|
||||||
/**
|
/**
|
||||||
* @param {object} config Rate limiter configuration object
|
* @param {object} config Rate limiter configuration object
|
||||||
*/
|
*/
|
||||||
constructor(config) {
|
constructor(config : KumaRateLimiterOpts) {
|
||||||
this.errorMessage = config.errorMessage;
|
this.errorMessage = config.errorMessage;
|
||||||
this.rateLimiter = new RateLimiter(config);
|
this.rateLimiter = new RateLimiter(config);
|
||||||
}
|
}
|
||||||
|
@ -24,11 +30,11 @@ class KumaRateLimiter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the request be passed through
|
* Should the request be passed through
|
||||||
* @param {passCB} callback Callback function to call with decision
|
* @param callback Callback function to call with decision
|
||||||
* @param {number} num Number of tokens to remove
|
* @param {number} num Number of tokens to remove
|
||||||
* @returns {Promise<boolean>} Should the request be allowed?
|
* @returns {Promise<boolean>} Should the request be allowed?
|
||||||
*/
|
*/
|
||||||
async pass(callback, num = 1) {
|
async pass(callback : KumaRateLimiterCallback, num = 1) {
|
||||||
const remainingRequests = await this.removeTokens(num);
|
const remainingRequests = await this.removeTokens(num);
|
||||||
log.info("rate-limit", "remaining requests: " + remainingRequests);
|
log.info("rate-limit", "remaining requests: " + remainingRequests);
|
||||||
if (remainingRequests < 0) {
|
if (remainingRequests < 0) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { DockgeServer } from "../dockgeServer";
|
import { DockgeServer } from "../dockge-server";
|
||||||
import { Router } from "../router";
|
import { Router } from "../router";
|
||||||
import express, { Express, Router as ExpressRouter } from "express";
|
import express, { Express, Router as ExpressRouter } from "express";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { R } from "redbean-node";
|
import { R } from "redbean-node";
|
||||||
import { log } from "./log";
|
import { log } from "./log";
|
||||||
|
import { LooseObject } from "./util-common";
|
||||||
|
|
||||||
export class Settings {
|
export class Settings {
|
||||||
|
|
||||||
|
@ -15,20 +16,19 @@ export class Settings {
|
||||||
* timestamp: 12345678
|
* timestamp: 12345678
|
||||||
* },
|
* },
|
||||||
* }
|
* }
|
||||||
* @type {{}}
|
|
||||||
*/
|
*/
|
||||||
static cacheList = {
|
static cacheList : LooseObject = {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static cacheCleaner = null;
|
static cacheCleaner? : NodeJS.Timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve value of setting based on key
|
* Retrieve value of setting based on key
|
||||||
* @param {string} key Key of setting to retrieve
|
* @param key Key of setting to retrieve
|
||||||
* @returns {Promise<any>} Value
|
* @returns Value
|
||||||
*/
|
*/
|
||||||
static async get(key) {
|
static async get(key : string) {
|
||||||
|
|
||||||
// Start cache clear if not started yet
|
// Start cache clear if not started yet
|
||||||
if (!Settings.cacheCleaner) {
|
if (!Settings.cacheCleaner) {
|
||||||
|
@ -72,12 +72,12 @@ export class Settings {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the specified setting to specified value
|
* Sets the specified setting to specified value
|
||||||
* @param {string} key Key of setting to set
|
* @param key Key of setting to set
|
||||||
* @param {any} value Value to set to
|
* @param value Value to set to
|
||||||
* @param {?string} type Type of setting
|
* @param {?string} type Type of setting
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async set(key, value, type = null) {
|
static async set(key : string, value : object | string | number | boolean, type : string | null = null) {
|
||||||
|
|
||||||
let bean = await R.findOne("setting", " `key` = ? ", [
|
let bean = await R.findOne("setting", " `key` = ? ", [
|
||||||
key,
|
key,
|
||||||
|
@ -95,15 +95,15 @@ export class Settings {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get settings based on type
|
* Get settings based on type
|
||||||
* @param {string} type The type of setting
|
* @param type The type of setting
|
||||||
* @returns {Promise<Bean>} Settings
|
* @returns Settings
|
||||||
*/
|
*/
|
||||||
static async getSettings(type) {
|
static async getSettings(type : string) {
|
||||||
const list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
|
const list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
|
||||||
type,
|
type,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const result = {};
|
const result : LooseObject = {};
|
||||||
|
|
||||||
for (const row of list) {
|
for (const row of list) {
|
||||||
try {
|
try {
|
||||||
|
@ -118,11 +118,11 @@ export class Settings {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set settings based on type
|
* Set settings based on type
|
||||||
* @param {string} type Type of settings to set
|
* @param type Type of settings to set
|
||||||
* @param {object} data Values of settings
|
* @param data Values of settings
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async setSettings(type, data) {
|
static async setSettings(type : string, data : LooseObject) {
|
||||||
const keyList = Object.keys(data);
|
const keyList = Object.keys(data);
|
||||||
|
|
||||||
const promiseList = [];
|
const promiseList = [];
|
||||||
|
@ -154,7 +154,7 @@ export class Settings {
|
||||||
* @param {string[]} keyList Keys to remove
|
* @param {string[]} keyList Keys to remove
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
static deleteCache(keyList) {
|
static deleteCache(keyList : string[]) {
|
||||||
for (const key of keyList) {
|
for (const key of keyList) {
|
||||||
delete Settings.cacheList[key];
|
delete Settings.cacheList[key];
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ export class Settings {
|
||||||
static stopCacheCleaner() {
|
static stopCacheCleaner() {
|
||||||
if (Settings.cacheCleaner) {
|
if (Settings.cacheCleaner) {
|
||||||
clearInterval(Settings.cacheCleaner);
|
clearInterval(Settings.cacheCleaner);
|
||||||
Settings.cacheCleaner = null;
|
Settings.cacheCleaner = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,27 @@ export class DockerSocketHandler extends SocketHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// down stack
|
||||||
|
socket.on("downStack", async (stackName : unknown, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket);
|
||||||
|
|
||||||
|
if (typeof(stackName) !== "string") {
|
||||||
|
throw new ValidationError("Stack name must be a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
const stack = Stack.getStack(server, stackName);
|
||||||
|
await stack.down(socket);
|
||||||
|
callback({
|
||||||
|
ok: true,
|
||||||
|
msg: "Downed"
|
||||||
|
});
|
||||||
|
server.sendStackList();
|
||||||
|
} catch (e) {
|
||||||
|
callbackError(e, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Services status
|
// Services status
|
||||||
socket.on("serviceStatusList", async (stackName : unknown, callback) => {
|
socket.on("serviceStatusList", async (stackName : unknown, callback) => {
|
||||||
try {
|
try {
|
||||||
|
@ -196,7 +217,7 @@ export class DockerSocketHandler extends SocketHandler {
|
||||||
throw new ValidationError("Stack name must be a string");
|
throw new ValidationError("Stack name must be a string");
|
||||||
}
|
}
|
||||||
|
|
||||||
const stack = Stack.getStack(server, stackName);
|
const stack = Stack.getStack(server, stackName, true);
|
||||||
const serviceStatusList = Object.fromEntries(await stack.getServiceStatusList());
|
const serviceStatusList = Object.fromEntries(await stack.getServiceStatusList());
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { SocketHandler } from "../socket-handler.js";
|
import { SocketHandler } from "../socket-handler.js";
|
||||||
import { Socket } from "socket.io";
|
|
||||||
import { DockgeServer } from "../dockge-server";
|
import { DockgeServer } from "../dockge-server";
|
||||||
import { log } from "../log";
|
import { log } from "../log";
|
||||||
import { R } from "redbean-node";
|
import { R } from "redbean-node";
|
||||||
import { loginRateLimiter, twoFaRateLimiter } from "../rate-limiter";
|
import { loginRateLimiter, twoFaRateLimiter } from "../rate-limiter";
|
||||||
import { generatePasswordHash, needRehashPassword, shake256, SHAKE256_LENGTH, verifyPassword } from "../password-hash";
|
import { generatePasswordHash, needRehashPassword, shake256, SHAKE256_LENGTH, verifyPassword } from "../password-hash";
|
||||||
import { User } from "../models/user";
|
import { User } from "../models/user";
|
||||||
import { checkLogin, DockgeSocket, doubleCheckPassword } from "../util-server";
|
import { checkLogin, DockgeSocket, doubleCheckPassword, JWTDecoded } from "../util-server";
|
||||||
import { passwordStrength } from "check-password-strength";
|
import { passwordStrength } from "check-password-strength";
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { Settings } from "../settings";
|
import { Settings } from "../settings";
|
||||||
|
@ -43,11 +42,13 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Login by token
|
// Login by token
|
||||||
|
@ -57,7 +58,7 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
log.info("auth", `Login by token. IP=${clientIP}`);
|
log.info("auth", `Login by token. IP=${clientIP}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = jwt.verify(token, server.jwtSecret);
|
const decoded = jwt.verify(token, server.jwtSecret) as JWTDecoded;
|
||||||
|
|
||||||
log.info("auth", "Username from JWT: " + decoded.username);
|
log.info("auth", "Username from JWT: " + decoded.username);
|
||||||
|
|
||||||
|
@ -91,9 +92,13 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (!(error instanceof Error)) {
|
||||||
|
console.error("Unknown error:", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.error("auth", `Invalid token. IP=${clientIP}`);
|
log.error("auth", `Invalid token. IP=${clientIP}`);
|
||||||
if (error.message) {
|
if (error.message) {
|
||||||
log.error("auth", error.message, `IP=${clientIP}`);
|
log.error("auth", error.message + ` IP=${clientIP}`);
|
||||||
}
|
}
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
@ -149,6 +154,7 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.token) {
|
if (data.token) {
|
||||||
|
// @ts-ignore
|
||||||
const verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions);
|
const verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions);
|
||||||
|
|
||||||
if (user.twofa_last_token !== data.token && verify) {
|
if (user.twofa_last_token !== data.token && verify) {
|
||||||
|
@ -211,11 +217,13 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("getSettings", async (callback) => {
|
socket.on("getSettings", async (callback) => {
|
||||||
|
@ -229,11 +237,13 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("setSettings", async (data, currentPassword, callback) => {
|
socket.on("setSettings", async (data, currentPassword, callback) => {
|
||||||
|
@ -262,22 +272,24 @@ export class MainSocketHandler extends SocketHandler {
|
||||||
server.sendInfo(socket);
|
server.sendInfo(socket);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
callback({
|
callback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(username : string, password : string) {
|
async login(username : string, password : string) : Promise<User | null> {
|
||||||
if (typeof username !== "string" || typeof password !== "string") {
|
if (typeof username !== "string" || typeof password !== "string") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await R.findOne("user", " username = ? AND active = 1 ", [
|
const user = await R.findOne("user", " username = ? AND active = 1 ", [
|
||||||
username,
|
username,
|
||||||
]);
|
]) as User;
|
||||||
|
|
||||||
if (user && verifyPassword(password, user.password)) {
|
if (user && verifyPassword(password, user.password)) {
|
||||||
// Upgrade the hash to bcrypt
|
// Upgrade the hash to bcrypt
|
||||||
|
|
|
@ -38,11 +38,13 @@ export class TerminalSocketHandler extends SocketHandler {
|
||||||
throw new Error("Terminal not found or it is not a Interactive Terminal.");
|
throw new Error("Terminal not found or it is not a Interactive Terminal.");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
errorCallback({
|
errorCallback({
|
||||||
ok: false,
|
ok: false,
|
||||||
msg: e.message,
|
msg: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Main Terminal
|
// Main Terminal
|
||||||
|
|
|
@ -24,16 +24,28 @@ export class Stack {
|
||||||
protected _status: number = UNKNOWN;
|
protected _status: number = UNKNOWN;
|
||||||
protected _composeYAML?: string;
|
protected _composeYAML?: string;
|
||||||
protected _configFilePath?: string;
|
protected _configFilePath?: string;
|
||||||
|
protected _composeFileName: string = "compose.yaml";
|
||||||
protected server: DockgeServer;
|
protected server: DockgeServer;
|
||||||
|
|
||||||
protected combinedTerminal? : Terminal;
|
protected combinedTerminal? : Terminal;
|
||||||
|
|
||||||
protected static managedStackList: Map<string, Stack> = new Map();
|
protected static managedStackList: Map<string, Stack> = new Map();
|
||||||
|
|
||||||
constructor(server : DockgeServer, name : string, composeYAML? : string) {
|
constructor(server : DockgeServer, name : string, composeYAML? : string, skipFSOperations = false) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this._composeYAML = composeYAML;
|
this._composeYAML = composeYAML;
|
||||||
|
|
||||||
|
if (!skipFSOperations) {
|
||||||
|
// Check if compose file name is different from compose.yaml
|
||||||
|
const supportedFileNames = [ "compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml" ];
|
||||||
|
for (const filename of supportedFileNames) {
|
||||||
|
if (fs.existsSync(path.join(this.path, filename))) {
|
||||||
|
this._composeFileName = filename;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() : object {
|
toJSON() : object {
|
||||||
|
@ -50,6 +62,7 @@ export class Stack {
|
||||||
status: this._status,
|
status: this._status,
|
||||||
tags: [],
|
tags: [],
|
||||||
isManagedByDockge: this.isManagedByDockge,
|
isManagedByDockge: this.isManagedByDockge,
|
||||||
|
composeFileName: this._composeFileName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +97,7 @@ export class Stack {
|
||||||
get composeYAML() : string {
|
get composeYAML() : string {
|
||||||
if (this._composeYAML === undefined) {
|
if (this._composeYAML === undefined) {
|
||||||
try {
|
try {
|
||||||
this._composeYAML = fs.readFileSync(path.join(this.path, "compose.yaml"), "utf-8");
|
this._composeYAML = fs.readFileSync(path.join(this.path, this._composeFileName), "utf-8");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._composeYAML = "";
|
this._composeYAML = "";
|
||||||
}
|
}
|
||||||
|
@ -135,7 +148,7 @@ export class Stack {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write or overwrite the compose.yaml
|
// Write or overwrite the compose.yaml
|
||||||
fs.writeFileSync(path.join(dir, "compose.yaml"), this.composeYAML);
|
fs.writeFileSync(path.join(dir, this._composeFileName), this.composeYAML);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deploy(socket? : DockgeSocket) : Promise<number> {
|
async deploy(socket? : DockgeSocket) : Promise<number> {
|
||||||
|
@ -163,10 +176,22 @@ export class Stack {
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateStatus() {
|
||||||
|
let statusList = Stack.getStatusList();
|
||||||
|
let status = statusList.get(this.name);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
this._status = status;
|
||||||
|
} else {
|
||||||
|
this._status = UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static getStackList(server : DockgeServer, useCacheForManaged = false) : Map<string, Stack> {
|
static getStackList(server : DockgeServer, useCacheForManaged = false) : Map<string, Stack> {
|
||||||
let stacksDir = server.stacksDir;
|
let stacksDir = server.stacksDir;
|
||||||
let stackList : Map<string, Stack>;
|
let stackList : Map<string, Stack>;
|
||||||
|
|
||||||
|
// Use cached stack list?
|
||||||
if (useCacheForManaged && this.managedStackList.size > 0) {
|
if (useCacheForManaged && this.managedStackList.size > 0) {
|
||||||
stackList = this.managedStackList;
|
stackList = this.managedStackList;
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,30 +211,29 @@ export class Stack {
|
||||||
stack._status = CREATED_FILE;
|
stack._status = CREATED_FILE;
|
||||||
stackList.set(filename, stack);
|
stackList.set(filename, stack);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
log.warn("getStackList", `Failed to get stack ${filename}, error: ${e.message}`);
|
log.warn("getStackList", `Failed to get stack ${filename}, error: ${e.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cache by copying
|
// Cache by copying
|
||||||
this.managedStackList = new Map(stackList);
|
this.managedStackList = new Map(stackList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also get the list from `docker compose ls --all --format json`
|
// Get status from docker compose ls
|
||||||
let res = childProcess.execSync("docker compose ls --all --format json");
|
let res = childProcess.execSync("docker compose ls --all --format json");
|
||||||
let composeList = JSON.parse(res.toString());
|
let composeList = JSON.parse(res.toString());
|
||||||
|
|
||||||
for (let composeStack of composeList) {
|
for (let composeStack of composeList) {
|
||||||
|
|
||||||
// Skip the dockge stack
|
|
||||||
// TODO: Could be self managed?
|
|
||||||
if (composeStack.Name === "dockge") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stack = stackList.get(composeStack.Name);
|
let stack = stackList.get(composeStack.Name);
|
||||||
|
|
||||||
// This stack probably is not managed by Dockge, but we still want to show it
|
// This stack probably is not managed by Dockge, but we still want to show it
|
||||||
if (!stack) {
|
if (!stack) {
|
||||||
|
// Skip the dockge stack if it is not managed by Dockge
|
||||||
|
if (composeStack.Name === "dockge") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
stack = new Stack(server, composeStack.Name);
|
stack = new Stack(server, composeStack.Name);
|
||||||
stackList.set(composeStack.Name, stack);
|
stackList.set(composeStack.Name, stack);
|
||||||
}
|
}
|
||||||
|
@ -240,26 +264,30 @@ export class Stack {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the status string from `docker compose ls` to the status number
|
* Convert the status string from `docker compose ls` to the status number
|
||||||
|
* Input Example: "exited(1), running(1)"
|
||||||
* @param status
|
* @param status
|
||||||
*/
|
*/
|
||||||
static statusConvert(status : string) : number {
|
static statusConvert(status : string) : number {
|
||||||
if (status.startsWith("created")) {
|
if (status.startsWith("created")) {
|
||||||
return CREATED_STACK;
|
return CREATED_STACK;
|
||||||
} else if (status.startsWith("running")) {
|
} else if (status.includes("exited")) {
|
||||||
return RUNNING;
|
// If one of the service is exited, we consider the stack is exited
|
||||||
} else if (status.startsWith("exited")) {
|
|
||||||
return EXITED;
|
return EXITED;
|
||||||
|
} else if (status.startsWith("running")) {
|
||||||
|
// If there is no exited services, there should be only running services
|
||||||
|
return RUNNING;
|
||||||
} else {
|
} else {
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getStack(server: DockgeServer, stackName: string) : Stack {
|
static getStack(server: DockgeServer, stackName: string, skipFSOperations = false) : Stack {
|
||||||
let dir = path.join(server.stacksDir, stackName);
|
let dir = path.join(server.stacksDir, stackName);
|
||||||
|
|
||||||
|
if (!skipFSOperations) {
|
||||||
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
||||||
// Maybe it is a stack managed by docker compose directly
|
// Maybe it is a stack managed by docker compose directly
|
||||||
let stackList = this.getStackList(server);
|
let stackList = this.getStackList(server, true);
|
||||||
let stack = stackList.get(stackName);
|
let stack = stackList.get(stackName);
|
||||||
|
|
||||||
if (stack) {
|
if (stack) {
|
||||||
|
@ -269,8 +297,18 @@ export class Stack {
|
||||||
throw new ValidationError("Stack not found");
|
throw new ValidationError("Stack not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("getStack", "Skip FS operations");
|
||||||
|
}
|
||||||
|
|
||||||
|
let stack : Stack;
|
||||||
|
|
||||||
|
if (!skipFSOperations) {
|
||||||
|
stack = new Stack(server, stackName);
|
||||||
|
} else {
|
||||||
|
stack = new Stack(server, stackName, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
let stack = new Stack(server, stackName);
|
|
||||||
stack._status = UNKNOWN;
|
stack._status = UNKNOWN;
|
||||||
stack._configFilePath = path.resolve(dir);
|
stack._configFilePath = path.resolve(dir);
|
||||||
return stack;
|
return stack;
|
||||||
|
@ -303,12 +341,29 @@ export class Stack {
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async down(socket: DockgeSocket) : Promise<number> {
|
||||||
|
const terminalName = getComposeTerminalName(this.name);
|
||||||
|
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "down" ], this.path);
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
throw new Error("Failed to down, please check the terminal output for more information.");
|
||||||
|
}
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
async update(socket: DockgeSocket) {
|
async update(socket: DockgeSocket) {
|
||||||
const terminalName = getComposeTerminalName(this.name);
|
const terminalName = getComposeTerminalName(this.name);
|
||||||
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "pull" ], this.path);
|
let exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "pull" ], this.path);
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
throw new Error("Failed to pull, please check the terminal output for more information.");
|
throw new Error("Failed to pull, please check the terminal output for more information.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the stack is not running, we don't need to restart it
|
||||||
|
this.updateStatus();
|
||||||
|
log.debug("update", "Status: " + this.status);
|
||||||
|
if (this.status !== RUNNING) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "up", "-d", "--remove-orphans" ], this.path);
|
exitCode = await Terminal.exec(this.server, socket, terminalName, "docker", [ "compose", "up", "-d", "--remove-orphans" ], this.path);
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
throw new Error("Failed to restart, please check the terminal output for more information.");
|
throw new Error("Failed to restart, please check the terminal output for more information.");
|
||||||
|
@ -342,16 +397,20 @@ export class Stack {
|
||||||
async getServiceStatusList() {
|
async getServiceStatusList() {
|
||||||
let statusList = new Map<string, number>();
|
let statusList = new Map<string, number>();
|
||||||
|
|
||||||
let res = childProcess.execSync("docker compose ps --format json", {
|
let res = childProcess.spawnSync("docker", [ "compose", "ps", "--format", "json" ], {
|
||||||
cwd: this.path,
|
cwd: this.path,
|
||||||
});
|
});
|
||||||
|
|
||||||
let lines = res.toString().split("\n");
|
let lines = res.stdout.toString().split("\n");
|
||||||
|
|
||||||
for (let line of lines) {
|
for (let line of lines) {
|
||||||
try {
|
try {
|
||||||
let obj = JSON.parse(line);
|
let obj = JSON.parse(line);
|
||||||
|
if (obj.Health === "") {
|
||||||
statusList.set(obj.Service, obj.State);
|
statusList.set(obj.Service, obj.State);
|
||||||
|
} else {
|
||||||
|
statusList.set(obj.Service, obj.Health);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,70 +46,6 @@ export class Terminal {
|
||||||
this.cwd = cwd;
|
this.cwd = cwd;
|
||||||
|
|
||||||
Terminal.terminalMap.set(this.name, this);
|
Terminal.terminalMap.set(this.name, this);
|
||||||
}
|
|
||||||
|
|
||||||
get rows() {
|
|
||||||
return this._rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
set rows(rows : number) {
|
|
||||||
this._rows = rows;
|
|
||||||
try {
|
|
||||||
this.ptyProcess?.resize(this.cols, this.rows);
|
|
||||||
} catch (e) {
|
|
||||||
log.debug("Terminal", "Failed to resize terminal: " + e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get cols() {
|
|
||||||
return this._cols;
|
|
||||||
}
|
|
||||||
|
|
||||||
set cols(cols : number) {
|
|
||||||
this._cols = cols;
|
|
||||||
try {
|
|
||||||
this.ptyProcess?.resize(this.cols, this.rows);
|
|
||||||
} catch (e) {
|
|
||||||
log.debug("Terminal", "Failed to resize terminal: " + e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public start() {
|
|
||||||
if (this._ptyProcess) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._ptyProcess = pty.spawn(this.file, this.args, {
|
|
||||||
name: this.name,
|
|
||||||
cwd: this.cwd,
|
|
||||||
cols: TERMINAL_COLS,
|
|
||||||
rows: this.rows,
|
|
||||||
});
|
|
||||||
|
|
||||||
// On Data
|
|
||||||
this._ptyProcess.onData((data) => {
|
|
||||||
this.buffer.push(data);
|
|
||||||
if (this.server.io) {
|
|
||||||
this.server.io.to(this.name).emit("terminalWrite", this.name, data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// On Exit
|
|
||||||
this._ptyProcess.onExit((res) => {
|
|
||||||
this.server.io.to(this.name).emit("terminalExit", this.name, res.exitCode);
|
|
||||||
|
|
||||||
// Remove room
|
|
||||||
this.server.io.in(this.name).socketsLeave(this.name);
|
|
||||||
|
|
||||||
Terminal.terminalMap.delete(this.name);
|
|
||||||
log.debug("Terminal", "Terminal " + this.name + " exited with code " + res.exitCode);
|
|
||||||
|
|
||||||
clearInterval(this.keepAliveInterval);
|
|
||||||
|
|
||||||
if (this.callback) {
|
|
||||||
this.callback(res.exitCode);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.enableKeepAlive) {
|
if (this.enableKeepAlive) {
|
||||||
log.debug("Terminal", "Keep alive enabled for terminal " + this.name);
|
log.debug("Terminal", "Keep alive enabled for terminal " + this.name);
|
||||||
|
@ -131,6 +67,90 @@ export class Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get rows() {
|
||||||
|
return this._rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
set rows(rows : number) {
|
||||||
|
this._rows = rows;
|
||||||
|
try {
|
||||||
|
this.ptyProcess?.resize(this.cols, this.rows);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
log.debug("Terminal", "Failed to resize terminal: " + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get cols() {
|
||||||
|
return this._cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
set cols(cols : number) {
|
||||||
|
this._cols = cols;
|
||||||
|
try {
|
||||||
|
this.ptyProcess?.resize(this.cols, this.rows);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
log.debug("Terminal", "Failed to resize terminal: " + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
if (this._ptyProcess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._ptyProcess = pty.spawn(this.file, this.args, {
|
||||||
|
name: this.name,
|
||||||
|
cwd: this.cwd,
|
||||||
|
cols: TERMINAL_COLS,
|
||||||
|
rows: this.rows,
|
||||||
|
});
|
||||||
|
|
||||||
|
// On Data
|
||||||
|
this._ptyProcess.onData((data) => {
|
||||||
|
this.buffer.pushItem(data);
|
||||||
|
if (this.server.io) {
|
||||||
|
this.server.io.to(this.name).emit("terminalWrite", this.name, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// On Exit
|
||||||
|
this._ptyProcess.onExit(this.exit);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
log.error("Terminal", "Failed to start terminal: " + error.message);
|
||||||
|
const exitCode = Number(error.message.split(" ").pop());
|
||||||
|
this.exit({
|
||||||
|
exitCode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exit event handler
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
protected exit = (res : {exitCode: number, signal?: number | undefined}) => {
|
||||||
|
this.server.io.to(this.name).emit("terminalExit", this.name, res.exitCode);
|
||||||
|
|
||||||
|
// Remove room
|
||||||
|
this.server.io.in(this.name).socketsLeave(this.name);
|
||||||
|
|
||||||
|
Terminal.terminalMap.delete(this.name);
|
||||||
|
log.debug("Terminal", "Terminal " + this.name + " exited with code " + res.exitCode);
|
||||||
|
|
||||||
|
clearInterval(this.keepAliveInterval);
|
||||||
|
|
||||||
|
if (this.callback) {
|
||||||
|
this.callback(res.exitCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public onExit(callback : (exitCode : number) => void) {
|
public onExit(callback : (exitCode : number) => void) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,11 @@ dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
|
export interface LooseObject {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
let randomBytes : (numBytes: number) => Uint8Array;
|
let randomBytes : (numBytes: number) => Uint8Array;
|
||||||
initRandomBytes();
|
initRandomBytes();
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,11 @@ import { ERROR_TYPE_VALIDATION } from "./util-common";
|
||||||
import { R } from "redbean-node";
|
import { R } from "redbean-node";
|
||||||
import { verifyPassword } from "./password-hash";
|
import { verifyPassword } from "./password-hash";
|
||||||
|
|
||||||
|
export interface JWTDecoded {
|
||||||
|
username : string;
|
||||||
|
h? : string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DockgeSocket extends Socket {
|
export interface DockgeSocket extends Socket {
|
||||||
userID: number;
|
userID: number;
|
||||||
consoleTerminal? : Terminal;
|
consoleTerminal? : Terminal;
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
*/
|
*/
|
||||||
export class LimitQueue<T> extends Array<T> {
|
export class LimitQueue<T> extends Array<T> {
|
||||||
__limit;
|
__limit;
|
||||||
__onExceed = null;
|
__onExceed? : (item : T | undefined) => void;
|
||||||
|
|
||||||
constructor(limit: number) {
|
constructor(limit: number) {
|
||||||
super();
|
super();
|
||||||
this.__limit = limit;
|
this.__limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
push(value : T) {
|
pushItem(value : T) {
|
||||||
super.push(value);
|
super.push(value);
|
||||||
if (this.length > this.__limit) {
|
if (this.length > this.__limit) {
|
||||||
const item = this.shift();
|
const item = this.shift();
|
||||||
|
|
57
extra/close-incorrect-issue.js
Normal file
57
extra/close-incorrect-issue.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import github from "@actions/github";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const token = process.argv[2];
|
||||||
|
const issueNumber = process.argv[3];
|
||||||
|
const username = process.argv[4];
|
||||||
|
|
||||||
|
const client = github.getOctokit(token).rest;
|
||||||
|
|
||||||
|
const issue = {
|
||||||
|
owner: "louislam",
|
||||||
|
repo: "dockge",
|
||||||
|
number: issueNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
const labels = (
|
||||||
|
await client.issues.listLabelsOnIssue({
|
||||||
|
owner: issue.owner,
|
||||||
|
repo: issue.repo,
|
||||||
|
issue_number: issue.number
|
||||||
|
})
|
||||||
|
).data.map(({ name }) => name);
|
||||||
|
|
||||||
|
if (labels.length === 0) {
|
||||||
|
console.log("Bad format here");
|
||||||
|
|
||||||
|
await client.issues.addLabels({
|
||||||
|
owner: issue.owner,
|
||||||
|
repo: issue.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: [ "invalid-format" ]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the issue closing comment
|
||||||
|
await client.issues.createComment({
|
||||||
|
owner: issue.owner,
|
||||||
|
repo: issue.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
body: `@${username}: Hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template. Please DO NOT open a blank issue.`
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close the issue
|
||||||
|
await client.issues.update({
|
||||||
|
owner: issue.owner,
|
||||||
|
repo: issue.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
state: "closed"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("Pass!");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
42
extra/reformat-changelog.ts
Normal file
42
extra/reformat-changelog.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Generate on GitHub
|
||||||
|
const input = `
|
||||||
|
* Add Korean translation by @Alanimdeo in https://github.com/louislam/dockge/pull/86
|
||||||
|
`;
|
||||||
|
|
||||||
|
const template = `
|
||||||
|
### 🆕 New Features
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
### 🦎 Translation Contributions
|
||||||
|
|
||||||
|
### Others
|
||||||
|
- Other small changes, code refactoring and comment/doc updates in this repo:
|
||||||
|
`;
|
||||||
|
|
||||||
|
const lines = input.split("\n").filter((line) => line.trim() !== "");
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
// Split the last " by "
|
||||||
|
const usernamePullRequesURL = line.split(" by ").pop();
|
||||||
|
|
||||||
|
if (!usernamePullRequesURL) {
|
||||||
|
console.log("Unable to parse", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ username, pullRequestURL ] = usernamePullRequesURL.split(" in ");
|
||||||
|
const pullRequestID = "#" + pullRequestURL.split("/").pop();
|
||||||
|
let message = line.split(" by ").shift();
|
||||||
|
|
||||||
|
if (!message) {
|
||||||
|
console.log("Unable to parse", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = message.split("* ").pop();
|
||||||
|
console.log("-", pullRequestID, message, `(Thanks ${username})`);
|
||||||
|
}
|
||||||
|
console.log(template);
|
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
|
@ -11,6 +11,8 @@ declare module 'vue' {
|
||||||
Appearance: typeof import('./src/components/settings/Appearance.vue')['default']
|
Appearance: typeof import('./src/components/settings/Appearance.vue')['default']
|
||||||
ArrayInput: typeof import('./src/components/ArrayInput.vue')['default']
|
ArrayInput: typeof import('./src/components/ArrayInput.vue')['default']
|
||||||
ArraySelect: typeof import('./src/components/ArraySelect.vue')['default']
|
ArraySelect: typeof import('./src/components/ArraySelect.vue')['default']
|
||||||
|
BDropdown: typeof import('bootstrap-vue-next')['BDropdown']
|
||||||
|
BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem']
|
||||||
BModal: typeof import('bootstrap-vue-next')['BModal']
|
BModal: typeof import('bootstrap-vue-next')['BModal']
|
||||||
Confirm: typeof import('./src/components/Confirm.vue')['default']
|
Confirm: typeof import('./src/components/Confirm.vue')['default']
|
||||||
Container: typeof import('./src/components/Container.vue')['default']
|
Container: typeof import('./src/components/Container.vue')['default']
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<li v-for="(value, index) in array" :key="index" class="list-group-item">
|
<li v-for="(value, index) in array" :key="index" class="list-group-item">
|
||||||
<select v-model="array[index]" class="no-bg domain-input">
|
<select v-model="array[index]" class="no-bg domain-input">
|
||||||
<option value="">Select a network...</option>
|
<option value="">Select a network...</option>
|
||||||
<option v-for="option in options" :value="option">{{ option }}</option>
|
<option v-for="option in options" :key="option" :value="option">{{ option }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<font-awesome-icon icon="times" class="action remove ms-2 me-3 text-danger" @click="remove(index)" />
|
<font-awesome-icon icon="times" class="action remove ms-2 me-3 text-danger" @click="remove(index)" />
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<div v-if="!isEditMode">
|
<div v-if="!isEditMode">
|
||||||
<span class="badge me-1" :class="bgStyle">{{ status }}</span>
|
<span class="badge me-1" :class="bgStyle">{{ status }}</span>
|
||||||
|
|
||||||
<a v-for="port in service.ports" :href="parsePort(port).url" target="_blank">
|
<a v-for="port in service.ports" :key="port" :href="parsePort(port).url" target="_blank">
|
||||||
<span class="badge me-1 bg-secondary">{{ parsePort(port).display }}</span>
|
<span class="badge me-1 bg-secondary">{{ parsePort(port).display }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<div v-if="isEditMode" class="mt-2">
|
<div v-if="isEditMode" class="mt-2">
|
||||||
<button class="btn btn-normal me-2" @click="showConfig = !showConfig">
|
<button class="btn btn-normal me-2" @click="showConfig = !showConfig">
|
||||||
<font-awesome-icon icon="edit" />
|
<font-awesome-icon icon="edit" />
|
||||||
Edit
|
{{ $t("Edit") }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="false" class="btn btn-normal me-2">Rename</button>
|
<button v-if="false" class="btn btn-normal me-2">Rename</button>
|
||||||
<button class="btn btn-danger me-2" @click="remove">
|
<button class="btn btn-danger me-2" @click="remove">
|
||||||
|
@ -179,8 +179,10 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
bgStyle() {
|
bgStyle() {
|
||||||
if (this.status === "running") {
|
if (this.status === "running" || this.status === "healthy") {
|
||||||
return "bg-primary";
|
return "bg-primary";
|
||||||
|
} else if (this.status === "unhealthy") {
|
||||||
|
return "bg-danger";
|
||||||
} else {
|
} else {
|
||||||
return "bg-secondary";
|
return "bg-secondary";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h5>Internal Networks</h5>
|
<h5>{{ $t("Internal Networks") }}</h5>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li v-for="(networkRow, index) in networkList" :key="index" class="list-group-item">
|
<li v-for="(networkRow, index) in networkList" :key="index" class="list-group-item">
|
||||||
<input v-model="networkRow.key" type="text" class="no-bg domain-input" placeholder="Network name..." />
|
<input v-model="networkRow.key" type="text" class="no-bg domain-input" placeholder="Network name..." />
|
||||||
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
<button class="btn btn-normal btn-sm mt-3 me-2" @click="addField">{{ $t("addInternalNetwork") }}</button>
|
<button class="btn btn-normal btn-sm mt-3 me-2" @click="addField">{{ $t("addInternalNetwork") }}</button>
|
||||||
|
|
||||||
<h5 class="mt-3">External Networks</h5>
|
<h5 class="mt-3">{{ $t("External Networks") }}</h5>
|
||||||
|
|
||||||
<div v-if="externalNetworkList.length === 0">
|
<div v-if="externalNetworkList.length === 0">
|
||||||
No External Networks
|
{{ $t("No External Networks") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="(networkName, index) in externalNetworkList" :key="networkName" class="form-check form-switch my-3">
|
<div v-for="(networkName, index) in externalNetworkList" :key="networkName" class="form-check form-switch my-3">
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
class="form-control"
|
class="form-control"
|
||||||
@keyup.enter="createExternelNetwork"
|
@keyup.enter="createExternelNetwork"
|
||||||
/>
|
/>
|
||||||
<button class="btn btn-normal btn-sm me-2" type="button" @click="">
|
<button class="btn btn-normal btn-sm me-2" type="button">
|
||||||
{{ $t("createExternalNetwork") }}
|
{{ $t("createExternalNetwork") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,7 +19,6 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
uptime() {
|
uptime() {
|
||||||
return "0.00%";
|
|
||||||
return this.$t("notAvailableShort");
|
return this.$t("notAvailableShort");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -46,6 +45,8 @@ export default {
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.badge {
|
.badge {
|
||||||
min-width: 62px;
|
min-width: 62px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fixed-width {
|
.fixed-width {
|
||||||
|
|
|
@ -47,10 +47,10 @@
|
||||||
<input
|
<input
|
||||||
v-model="settings.primaryHostname"
|
v-model="settings.primaryHostname"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder="localhost"
|
placeholder="(Unset: Follow current hostname)"
|
||||||
/>
|
/>
|
||||||
<button class="btn btn-outline-primary" type="button" @click="autoGetPrimaryHostname">
|
<button class="btn btn-outline-primary" type="button" @click="autoGetPrimaryHostname">
|
||||||
{{ $t("Auto Get") }}
|
{{ $t("autoGet") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -68,13 +68,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HiddenInput from "../../components/HiddenInput.vue";
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { timezoneList } from "../../util-frontend";
|
import { timezoneList } from "../../util-frontend";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
HiddenInput,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
|
|
@ -3,7 +3,24 @@ import { createI18n } from "vue-i18n/dist/vue-i18n.esm-browser.prod.js";
|
||||||
import en from "./lang/en.json";
|
import en from "./lang/en.json";
|
||||||
|
|
||||||
const languageList = {
|
const languageList = {
|
||||||
|
"bg-BG": "Български",
|
||||||
|
"es": "Español",
|
||||||
|
"de": "Deutsch",
|
||||||
|
"fr": "Français",
|
||||||
|
"pl-PL": "Polski",
|
||||||
|
"pt": "Português",
|
||||||
|
"pt-BR": "Português-Brasil",
|
||||||
|
"sl": "Slovenščina",
|
||||||
|
"tr": "Türkçe",
|
||||||
|
"zh-CN": "简体中文",
|
||||||
|
"ur": "Urdu",
|
||||||
|
"ko-KR": "한국어",
|
||||||
|
"ru": "Русский",
|
||||||
|
"cs-CZ": "Čeština",
|
||||||
|
"ar": "العربية",
|
||||||
|
"th":"ไทย",
|
||||||
|
"it-IT":"Italiano",
|
||||||
|
"sv-SE":"Svenska"
|
||||||
};
|
};
|
||||||
|
|
||||||
let messages = {
|
let messages = {
|
||||||
|
|
14
frontend/src/lang/README.md
Normal file
14
frontend/src/lang/README.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Translations
|
||||||
|
|
||||||
|
A simple guide on how to translate `Dockge` in your native language.
|
||||||
|
|
||||||
|
## How to add a new language in the dropdown
|
||||||
|
|
||||||
|
(11-21-2023) Updated
|
||||||
|
|
||||||
|
1. Add your Language at `frontend/src/lang/` by creating a new file with your language Code, format: `zh-TW.json` .
|
||||||
|
2. Copy the content from `en.json` and make translations from that.
|
||||||
|
3. Add your language at the end of `languageList` in `frontend/src/i18n.ts`, format: `"zh-TW": "繁體中文 (台灣)"`,
|
||||||
|
4. Commit to new branch and make a new Pull Request for me to approve.
|
||||||
|
|
||||||
|
*Note:* Currently we are only accepting one Pull Request per Language Translate.
|
95
frontend/src/lang/ar.json
Normal file
95
frontend/src/lang/ar.json
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"languageName": "العربية",
|
||||||
|
"Create your admin account": "إنشاء حساب المشرف",
|
||||||
|
"authIncorrectCreds": "اسم المستخدم أو كلمة المرور غير صحيحة.",
|
||||||
|
"PasswordsDoNotMatch": "كلمة المرور غير مطابقة.",
|
||||||
|
"Repeat Password": "أعد كتابة كلمة السر",
|
||||||
|
"Create": "إنشاء",
|
||||||
|
"signedInDisp": "تم تسجيل الدخول باسم {0}",
|
||||||
|
"signedInDispDisabled": "تم تعطيل المصادقة.",
|
||||||
|
"home": "الرئيسية",
|
||||||
|
"console": "سطر الأوامر",
|
||||||
|
"registry": "السجل",
|
||||||
|
"compose": "أنشاء كمبوز",
|
||||||
|
"addFirstStackMsg": "أنشيء أول كمبوز!",
|
||||||
|
"stackName" : "اسم المكدسة",
|
||||||
|
"deployStack": "شنر",
|
||||||
|
"deleteStack": "حذف",
|
||||||
|
"stopStack": "إيقاف",
|
||||||
|
"restartStack": "إعادة تشغيل",
|
||||||
|
"updateStack": "تحديث",
|
||||||
|
"startStack": "تشغيل",
|
||||||
|
"downStack": "أيقاف",
|
||||||
|
"editStack": "تعديل",
|
||||||
|
"discardStack": "إهمال",
|
||||||
|
"saveStackDraft": "حفظ",
|
||||||
|
"notAvailableShort" : "غير متوفر",
|
||||||
|
"deleteStackMsg": "هل أنت متأكد أنك تريد حذف هذه المكدسة؟",
|
||||||
|
"stackNotManagedByDockgeMsg": "لا يتم إدارة هذه المكدس بواسطة Dockge.",
|
||||||
|
"primaryHostname": "اسم المضيف الرئيسي",
|
||||||
|
"general": "عام",
|
||||||
|
"container": "حاوية | حاويات",
|
||||||
|
"scanFolder": "مسح مجلد المكدسات",
|
||||||
|
"dockerImage": "صورة",
|
||||||
|
"restartPolicyUnlessStopped": "ما لم يوقف",
|
||||||
|
"restartPolicyAlways": "دائماً",
|
||||||
|
"restartPolicyOnFailure": "عند الفشل",
|
||||||
|
"restartPolicyNo": "لا",
|
||||||
|
"environmentVariable": "متغير البيئة | متغيرات البيئة",
|
||||||
|
"restartPolicy": "سياسة إعادة التشغيل",
|
||||||
|
"containerName": "اسم الحاوية",
|
||||||
|
"port": "منفذ | منافذ",
|
||||||
|
"volume": "مجلد | مجلدات",
|
||||||
|
"network": "شبكة | شبكات",
|
||||||
|
"dependsOn": "تبعية الحاوية | تبعية الحاويات",
|
||||||
|
"addListItem": "إضافة {0}",
|
||||||
|
"deleteContainer": "حذف",
|
||||||
|
"addContainer": "أضافة حاوية",
|
||||||
|
"addNetwork": "أضافة شبكة",
|
||||||
|
"disableauth.message1": "هل أنت متأكد أنك تريد <strong>تعطيل المصادقة</strong>?",
|
||||||
|
"disableauth.message2": "إنه مصمم للحالات <strong>التي تنوي فيها مصادقة الطرف الثالث</strong> أمام Dockge مثل Cloudflare Access, Authelia أو أي من آليات المصادقة الأخرى.",
|
||||||
|
"passwordNotMatchMsg": "كلمة المرور المكررة غير متطابقة.",
|
||||||
|
"autoGet": "الجلب التلقائي",
|
||||||
|
"add": "إضافة",
|
||||||
|
"Edit": "تعديل",
|
||||||
|
"applyToYAML": "تطبيق على YAML",
|
||||||
|
"createExternalNetwork": "إنشاء",
|
||||||
|
"addInternalNetwork": "إضافة",
|
||||||
|
"Save": "حفظ",
|
||||||
|
"Language": "اللغة",
|
||||||
|
"Current User": "المستخدم الحالي",
|
||||||
|
"Change Password": "تعديل كلمة المرور",
|
||||||
|
"Current Password": "كلمة المرور الحالية",
|
||||||
|
"New Password": "كلمة مرور جديدة",
|
||||||
|
"Repeat New Password": "أعد تكرار كلمة المرور",
|
||||||
|
"Update Password": "تحديث كلمة المرور",
|
||||||
|
"Advanced": "متقدم",
|
||||||
|
"Please use this option carefully!": "من فضلك استخدم هذا الخيار بعناية!",
|
||||||
|
"Enable Auth": "تفعيل المصادقة",
|
||||||
|
"Disable Auth": "تعطيل المصادقة",
|
||||||
|
"I understand, please disable": "أتفهم, أرجو التعطيل",
|
||||||
|
"Leave": "مغادرة",
|
||||||
|
"Frontend Version": "لإصدار الواجهة الأمامية",
|
||||||
|
"Check Update On GitHub": "تحق من التحديث على GitHub",
|
||||||
|
"Show update if available": "اعرض التحديث إذا كان متاحًا",
|
||||||
|
"Also check beta release": "تحقق أيضًا من إصدار النسخة التجريبية",
|
||||||
|
"Remember me": "تذكرني",
|
||||||
|
"Login": "تسجيل الدخول",
|
||||||
|
"Username": "اسم المستخدم",
|
||||||
|
"Password": "كلمة المرور",
|
||||||
|
"Settings": "الاعدادات",
|
||||||
|
"Logout": "تسجيل الخروج",
|
||||||
|
"Lowercase only": "أحرف صغيرة فقط",
|
||||||
|
"Convert to Compose": "تحويل إلى كومبوز",
|
||||||
|
"Docker Run": "تشغيل Docker",
|
||||||
|
"active": "نشيط",
|
||||||
|
"exited": "تم الخروج",
|
||||||
|
"inactive": "غير نشيط",
|
||||||
|
"Appearance": "المظهر",
|
||||||
|
"Security": "الأمان",
|
||||||
|
"About": "حول",
|
||||||
|
"Allowed commands:": "الأوامر المسموح بها:",
|
||||||
|
"Internal Networks": "الشبكات الداخلية",
|
||||||
|
"External Networks": "الشبكات الخارجية",
|
||||||
|
"No External Networks": "لا توجد شبكات خارجية"
|
||||||
|
}
|
94
frontend/src/lang/bg-BG.json
Normal file
94
frontend/src/lang/bg-BG.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Български",
|
||||||
|
"Create your admin account": "Създайте администраторски профил",
|
||||||
|
"authIncorrectCreds": "Грешно име или парола.",
|
||||||
|
"PasswordsDoNotMatch": "Паролите не съвпадат.",
|
||||||
|
"Repeat Password": "Повторете паролата",
|
||||||
|
"Create": "Създай",
|
||||||
|
"signedInDisp": "Вписан като {0}",
|
||||||
|
"signedInDispDisabled": "Удостоверяването е изключено.",
|
||||||
|
"home": "Начало",
|
||||||
|
"console": "Конзола",
|
||||||
|
"registry": "Регистър",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Създайте вашия първи стак!",
|
||||||
|
"stackName" : "Име на стак",
|
||||||
|
"deployStack": "Разположи",
|
||||||
|
"deleteStack": "Изтрий",
|
||||||
|
"stopStack": "Спри",
|
||||||
|
"restartStack": "Рестартирай",
|
||||||
|
"updateStack": "Актуализирай",
|
||||||
|
"startStack": "Стартирай",
|
||||||
|
"editStack": "Редактирай",
|
||||||
|
"discardStack": "Отхвърли",
|
||||||
|
"saveStackDraft": "Запази",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Сигурни ли сте, че желаете да изтриете този стак?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Този стак не се управлява от Dockge.",
|
||||||
|
"primaryHostname": "Основно име на хост",
|
||||||
|
"general": "Общи",
|
||||||
|
"container": "Контейнер | Контейнери",
|
||||||
|
"scanFolder": "Сканиране папката със стакове",
|
||||||
|
"dockerImage": "Изображение",
|
||||||
|
"restartPolicyUnlessStopped": "Докато не бъде спрян",
|
||||||
|
"restartPolicyAlways": "Винаги",
|
||||||
|
"restartPolicyOnFailure": "При неуспех",
|
||||||
|
"restartPolicyNo": "Не",
|
||||||
|
"environmentVariable": "Променлива на средата | Променливи на средата",
|
||||||
|
"restartPolicy": "Правила за рестартиране",
|
||||||
|
"containerName": "Име на контейнер",
|
||||||
|
"port": "Порт | Портове",
|
||||||
|
"volume": "Том | Томове",
|
||||||
|
"network": "Мрежа | Мрежи",
|
||||||
|
"dependsOn": "Зависимост от контейнер | Зависимост от контейнери",
|
||||||
|
"addListItem": "Добави {0}",
|
||||||
|
"deleteContainer": "Изтрий",
|
||||||
|
"addContainer": "Добави контейнер",
|
||||||
|
"addNetwork": "Добави мрежа",
|
||||||
|
"disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?",
|
||||||
|
"disableauth.message2": "Използва се в случаите, <strong>когато има настроен алтернативен метод за удостоверяване</strong> преди Dockge, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.",
|
||||||
|
"passwordNotMatchMsg": "Повторената парола не съвпада.",
|
||||||
|
"autoGet": "Автоматично получаване",
|
||||||
|
"add": "Добави",
|
||||||
|
"Edit": "Редактирай",
|
||||||
|
"applyToYAML": "Приложи към YAML",
|
||||||
|
"createExternalNetwork": "Създай",
|
||||||
|
"addInternalNetwork": "Добави",
|
||||||
|
"Save": "Запиши",
|
||||||
|
"Language": "Език",
|
||||||
|
"Current User": "Текущ потребител",
|
||||||
|
"Change Password": "Промени парола",
|
||||||
|
"Current Password": "Текуща парола",
|
||||||
|
"New Password": "Нова парола",
|
||||||
|
"Repeat New Password": "Повторете новата парола",
|
||||||
|
"Update Password": "Актуализирай парола",
|
||||||
|
"Advanced": "Разширени",
|
||||||
|
"Please use this option carefully!": "Моля, използвайте с повишено внимание!",
|
||||||
|
"Enable Auth": "Включи удостоверяване",
|
||||||
|
"Disable Auth": "Изключи удостоверяване",
|
||||||
|
"I understand, please disable": "Разбирам. Моля, изключи",
|
||||||
|
"Leave": "Напусни",
|
||||||
|
"Frontend Version": "Фронтенд версия",
|
||||||
|
"Check Update On GitHub": "Проверка за актуализация в GitHub",
|
||||||
|
"Show update if available": "Покажи актуализация, ако е налична",
|
||||||
|
"Also check beta release": "Проверявай и за бета версии",
|
||||||
|
"Remember me": "Запомни ме",
|
||||||
|
"Login": "Вписване",
|
||||||
|
"Username": "Потребител",
|
||||||
|
"Password": "Парола",
|
||||||
|
"Settings": "Настройки",
|
||||||
|
"Logout": "Изход",
|
||||||
|
"Lowercase only": "Само малки букви",
|
||||||
|
"Convert to Compose": "Конвертирай в \"Compose\" формат",
|
||||||
|
"Docker Run": "Стартирай Docker",
|
||||||
|
"active": "активен",
|
||||||
|
"exited": "излязъл",
|
||||||
|
"inactive": "неактивен",
|
||||||
|
"Appearance": "Изглед",
|
||||||
|
"Security": "Сигурност",
|
||||||
|
"About": "Относно",
|
||||||
|
"Allowed commands:": "Позволени команди:",
|
||||||
|
"Internal Networks": "Вътрешни мрежи",
|
||||||
|
"External Networks": "Външни мрежи",
|
||||||
|
"No External Networks": "Не са налични външни мрежи"
|
||||||
|
}
|
95
frontend/src/lang/cs-CZ.json
Normal file
95
frontend/src/lang/cs-CZ.json
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"languageName": "Čeština",
|
||||||
|
"Create your admin account": "Vytvořit účet administrátora",
|
||||||
|
"authIncorrectCreds": "Nesprávné uživatelské jméno nebo heslo.",
|
||||||
|
"PasswordsDoNotMatch": "Hesla se neshodují.",
|
||||||
|
"Repeat Password": "Opakujte heslo",
|
||||||
|
"Create": "Vytvořit",
|
||||||
|
"signedInDisp": "Přihlášen jako {0}",
|
||||||
|
"signedInDispDisabled": "Ověření zakázáno.",
|
||||||
|
"home": "Domů",
|
||||||
|
"console": "Konzole",
|
||||||
|
"registry": "Registry",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Vytvořte svůj první stack!",
|
||||||
|
"stackName": "Název stacku",
|
||||||
|
"deployStack": "Nainstalovat",
|
||||||
|
"deleteStack": "Smazat",
|
||||||
|
"stopStack": "Zastavit",
|
||||||
|
"restartStack": "Restartovat",
|
||||||
|
"updateStack": "Aktualizovat",
|
||||||
|
"startStack": "Spustit",
|
||||||
|
"downStack": "Zastavit a vypnout",
|
||||||
|
"editStack": "Upravit",
|
||||||
|
"discardStack": "Zahodit",
|
||||||
|
"saveStackDraft": "Uložit",
|
||||||
|
"notAvailableShort": "N/A",
|
||||||
|
"deleteStackMsg": "Opravdu chcete smazat tento stack?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Tento stack není spravován systémem Dockge.",
|
||||||
|
"primaryHostname": "Primární název hostitele",
|
||||||
|
"general": "Obecné",
|
||||||
|
"container": "Kontejner | Kontejnery",
|
||||||
|
"scanFolder": "Prohledat složku se stacky",
|
||||||
|
"dockerImage": "Obrázek",
|
||||||
|
"restartPolicyUnlessStopped": "Pokud není zastaveno",
|
||||||
|
"restartPolicyAlways": "Vždy",
|
||||||
|
"restartPolicyOnFailure": "Při selhání",
|
||||||
|
"restartPolicyNo": "Ne",
|
||||||
|
"environmentVariable": "Proměnná prostředí | Proměnné prostředí",
|
||||||
|
"restartPolicy": "Politika restartu",
|
||||||
|
"containerName": "Název kontejneru",
|
||||||
|
"port": "Port | Porty",
|
||||||
|
"volume": "Svazek | Svazky",
|
||||||
|
"network": "Síť | Sítě",
|
||||||
|
"dependsOn": "Závisí na kontejneru | Závislosti na kontejneru",
|
||||||
|
"addListItem": "Přidat {0}",
|
||||||
|
"deleteContainer": "Smazat",
|
||||||
|
"addContainer": "Přidat kontejner",
|
||||||
|
"addNetwork": "Přidat síť",
|
||||||
|
"disableauth.message1": "Opravdu chcete <strong>zakázat ověřování</strong>?",
|
||||||
|
"disableauth.message2": "Je navrženo pro scénáře, kde <strong>plánujete implementovat ověřování třetí strany</strong> před Dockge, například Cloudflare Access, Authelia nebo jiné ověřovací mechanismy.",
|
||||||
|
"passwordNotMatchMsg": "Hesla se neshodují.",
|
||||||
|
"autoGet": "Automaticky získat",
|
||||||
|
"add": "Přidat",
|
||||||
|
"Edit": "Upravit",
|
||||||
|
"applyToYAML": "Použít na YAML",
|
||||||
|
"createExternalNetwork": "Vytvořit",
|
||||||
|
"addInternalNetwork": "Přidat",
|
||||||
|
"Save": "Uložit",
|
||||||
|
"Language": "Jazyk",
|
||||||
|
"Current User": "Aktuální uživatel",
|
||||||
|
"Change Password": "Změnit heslo",
|
||||||
|
"Current Password": "Aktuální heslo",
|
||||||
|
"New Password": "Nové heslo",
|
||||||
|
"Repeat New Password": "Opakujte nové heslo",
|
||||||
|
"Update Password": "Aktualizovat heslo",
|
||||||
|
"Advanced": "Pokročilé",
|
||||||
|
"Please use this option carefully!": "Používejte tuto možnost opatrně!",
|
||||||
|
"Enable Auth": "Povolit ověřování",
|
||||||
|
"Disable Auth": "Zakázat ověřování",
|
||||||
|
"I understand, please disable": "Rozumím, prosím zakážte",
|
||||||
|
"Leave": "Opustit",
|
||||||
|
"Frontend Version": "Verze rozhraní",
|
||||||
|
"Check Update On GitHub": "Zkontrolovat aktualizaci na GitHubu",
|
||||||
|
"Show update if available": "Zobrazit aktualizaci, pokud je k dispozici",
|
||||||
|
"Also check beta release": "Zkontrolovat také beta verzi",
|
||||||
|
"Remember me": "Zapamatovat údaje",
|
||||||
|
"Login": "Přihlásit se",
|
||||||
|
"Username": "Uživatelské jméno",
|
||||||
|
"Password": "Heslo",
|
||||||
|
"Settings": "Nastavení",
|
||||||
|
"Logout": "Odhlásit se",
|
||||||
|
"Lowercase only": "Pouze malá písmena",
|
||||||
|
"Convert to Compose": "Převést na Compose",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "Aktivní",
|
||||||
|
"exited": "Ukončený",
|
||||||
|
"inactive": "Neaktivní",
|
||||||
|
"Appearance": "Vzhled",
|
||||||
|
"Security": "Zabezpečení",
|
||||||
|
"About": "O aplikaci",
|
||||||
|
"Allowed commands:": "Povolené příkazy:",
|
||||||
|
"Internal Networks": "Interní sítě",
|
||||||
|
"External Networks": "Externí sítě",
|
||||||
|
"No External Networks": "Žádné externí sítě"
|
||||||
|
}
|
94
frontend/src/lang/de.json
Normal file
94
frontend/src/lang/de.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Deutsch",
|
||||||
|
"Create your admin account": "Erstelle dein Admin-Konto",
|
||||||
|
"authIncorrectCreds": "Falscher Benutzername oder falsches Passwort.",
|
||||||
|
"PasswordsDoNotMatch": "Passwörter stimmen nicht überein.",
|
||||||
|
"Repeat Password": "Passwort wiederholen",
|
||||||
|
"Create": "Erstellen",
|
||||||
|
"signedInDisp": "Angemeldet als {0}",
|
||||||
|
"signedInDispDisabled": "Authentifizierung deaktiviert.",
|
||||||
|
"home": "Startseite",
|
||||||
|
"console": "Konsole",
|
||||||
|
"registry": "Register",
|
||||||
|
"compose": "Zusammenstellen",
|
||||||
|
"addFirstStackMsg": "Stelle deinen ersten Stack zusammen!",
|
||||||
|
"stackName" : "Stack-Name",
|
||||||
|
"deployStack": "Bereitstellen",
|
||||||
|
"deleteStack": "Löschen",
|
||||||
|
"stopStack": "Anhalten",
|
||||||
|
"restartStack": "Neustarten",
|
||||||
|
"updateStack": "Aktualisieren",
|
||||||
|
"startStack": "Starten",
|
||||||
|
"editStack": "Bearbeiten",
|
||||||
|
"discardStack": "Verwerfen",
|
||||||
|
"saveStackDraft": "Speichern",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Möchtest du diesen Stack wirklich löschen?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Dieser Stack wird nicht von Dockge verwaltet.",
|
||||||
|
"primaryHostname": "Primärer Hostname",
|
||||||
|
"general": "Allgemein",
|
||||||
|
"container": "Container | Container",
|
||||||
|
"scanFolder": "Stacks-Ordner durchsuchen",
|
||||||
|
"dockerImage": "Image",
|
||||||
|
"restartPolicyUnlessStopped": "Falls nicht gestoppt",
|
||||||
|
"restartPolicyAlways": "Immer",
|
||||||
|
"restartPolicyOnFailure": "Bei Fehler",
|
||||||
|
"restartPolicyNo": "Kein Neustart",
|
||||||
|
"environmentVariable": "Umgebungsvariable | Umgebungsvariablen",
|
||||||
|
"restartPolicy": "Neustart Richtlinie",
|
||||||
|
"containerName": "Container-Name",
|
||||||
|
"port": "Port | Ports",
|
||||||
|
"volume": "Volume | Volumes",
|
||||||
|
"network": "Netzwerk | Netzwerke",
|
||||||
|
"dependsOn": "Container-Abhängigkeit | Container-Abhängigkeiten",
|
||||||
|
"addListItem": "{0} hinzufügen",
|
||||||
|
"deleteContainer": "Löschen",
|
||||||
|
"addContainer": "Container hinzufügen",
|
||||||
|
"addNetwork": "Netzwerk hinzufügen",
|
||||||
|
"disableauth.message1": "Bist du sicher, dass du die <strong>Authentifizierung deaktivieren</strong> möchtest?",
|
||||||
|
"disableauth.message2": "Es ist für Szenarien vorgesehen, <strong>in denen du beabsichtigst, eine Drittanbieter-Authentifizierung</strong> vor Dockge zu implementieren, wie zum Beispiel Cloudflare Access, Authelia oder andere Authentifizierungsmechanismen.",
|
||||||
|
"passwordNotMatchMsg": "Das wiederholte Passwort stimmt nicht überein.",
|
||||||
|
"autoGet": "Automatisch holen",
|
||||||
|
"add": "Hinzufügen",
|
||||||
|
"Edit": "Bearbeiten",
|
||||||
|
"applyToYAML": "Auf YAML anwenden",
|
||||||
|
"createExternalNetwork": "Erstellen",
|
||||||
|
"addInternalNetwork": "Hinzufügen",
|
||||||
|
"Save": "Speichern",
|
||||||
|
"Language": "Sprache",
|
||||||
|
"Current User": "Aktueller Benutzer",
|
||||||
|
"Change Password": "Passwort ändern",
|
||||||
|
"Current Password": "Aktuelles Passwort",
|
||||||
|
"New Password": "Neues Passwort",
|
||||||
|
"Repeat New Password": "Neues Passwort wiederholen",
|
||||||
|
"Update Password": "Passwort aktualisieren",
|
||||||
|
"Advanced": "Erweitert",
|
||||||
|
"Please use this option carefully!": "Bitte verwende diese Option sorgfältig!",
|
||||||
|
"Enable Auth": "Authentifizierung aktivieren",
|
||||||
|
"Disable Auth": "Authentifizierung deaktivieren",
|
||||||
|
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
|
||||||
|
"Leave": "Verlassen",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Check Update On GitHub": "Update auf GitHub überprüfen",
|
||||||
|
"Show update if available": "Update anzeigen, wenn verfügbar",
|
||||||
|
"Also check beta release": "Auch Beta-Version überprüfen",
|
||||||
|
"Remember me": "Anmeldung beibehalten",
|
||||||
|
"Login": "Anmelden",
|
||||||
|
"Username": "Benutzername",
|
||||||
|
"Password": "Passwort",
|
||||||
|
"Settings": "Einstellungen",
|
||||||
|
"Logout": "Abmelden",
|
||||||
|
"Lowercase only": "Nur Kleinbuchstaben",
|
||||||
|
"Convert to Compose": "In Compose Syntax umwandeln",
|
||||||
|
"Docker Run": "Docker ausführen",
|
||||||
|
"active": "aktiv",
|
||||||
|
"exited": "beendet",
|
||||||
|
"inactive": "inaktiv",
|
||||||
|
"Appearance": "Erscheinungsbild",
|
||||||
|
"Security": "Sicherheit",
|
||||||
|
"About": "Über",
|
||||||
|
"Allowed commands:": "Zugelassene Befehle:",
|
||||||
|
"Internal Networks": "Interne Netzwerke",
|
||||||
|
"External Networks": "Externe Netzwerke",
|
||||||
|
"No External Networks": "Keine externen Netzwerke"
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
{
|
{
|
||||||
"languageName": "English",
|
"languageName": "English",
|
||||||
|
"Create your admin account": "Create your admin account",
|
||||||
"authIncorrectCreds": "Incorrect username or password.",
|
"authIncorrectCreds": "Incorrect username or password.",
|
||||||
"PasswordsDoNotMatch": "Passwords do not match.",
|
"PasswordsDoNotMatch": "Passwords do not match.",
|
||||||
|
"Repeat Password": "Repeat Password",
|
||||||
|
"Create": "Create",
|
||||||
"signedInDisp": "Signed in as {0}",
|
"signedInDisp": "Signed in as {0}",
|
||||||
"signedInDispDisabled": "Auth Disabled.",
|
"signedInDispDisabled": "Auth Disabled.",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
|
@ -16,6 +19,7 @@
|
||||||
"restartStack": "Restart",
|
"restartStack": "Restart",
|
||||||
"updateStack": "Update",
|
"updateStack": "Update",
|
||||||
"startStack": "Start",
|
"startStack": "Start",
|
||||||
|
"downStack": "Stop & Down",
|
||||||
"editStack": "Edit",
|
"editStack": "Edit",
|
||||||
"discardStack": "Discard",
|
"discardStack": "Discard",
|
||||||
"saveStackDraft": "Save",
|
"saveStackDraft": "Save",
|
||||||
|
@ -43,11 +47,49 @@
|
||||||
"addContainer": "Add Container",
|
"addContainer": "Add Container",
|
||||||
"addNetwork": "Add Network",
|
"addNetwork": "Add Network",
|
||||||
"disableauth.message1": "Are you sure want to <strong>disable authentication</strong>?",
|
"disableauth.message1": "Are you sure want to <strong>disable authentication</strong>?",
|
||||||
"disableauth.message2": "It is designed for scenarios <strong>where you intend to implement third-party authentication</strong> in front of Uptime Kuma such as Cloudflare Access, Authelia or other authentication mechanisms.",
|
"disableauth.message2": "It is designed for scenarios <strong>where you intend to implement third-party authentication</strong> in front of Dockge such as Cloudflare Access, Authelia or other authentication mechanisms.",
|
||||||
"passwordNotMatchMsg": "The repeat password does not match.",
|
"passwordNotMatchMsg": "The repeat password does not match.",
|
||||||
"autoGet": "Auto Get",
|
"autoGet": "Auto Get",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
|
"Edit": "Edit",
|
||||||
"applyToYAML": "Apply to YAML",
|
"applyToYAML": "Apply to YAML",
|
||||||
"createExternalNetwork": "Create",
|
"createExternalNetwork": "Create",
|
||||||
"addInternalNetwork": "Add"
|
"addInternalNetwork": "Add",
|
||||||
|
"Save": "Save",
|
||||||
|
"Language": "Language",
|
||||||
|
"Current User": "Current User",
|
||||||
|
"Change Password": "Change Password",
|
||||||
|
"Current Password": "Current Password",
|
||||||
|
"New Password": "New Password",
|
||||||
|
"Repeat New Password": "Repeat New Password",
|
||||||
|
"Update Password": "Update Password",
|
||||||
|
"Advanced": "Advanced",
|
||||||
|
"Please use this option carefully!": "Please use this option carefully!",
|
||||||
|
"Enable Auth": "Enable Auth",
|
||||||
|
"Disable Auth": "Disable Auth",
|
||||||
|
"I understand, please disable": "I understand, please disable",
|
||||||
|
"Leave": "Leave",
|
||||||
|
"Frontend Version": "Frontend Version",
|
||||||
|
"Check Update On GitHub": "Check Update On GitHub",
|
||||||
|
"Show update if available": "Show update if available",
|
||||||
|
"Also check beta release": "Also check beta release",
|
||||||
|
"Remember me": "Remember me",
|
||||||
|
"Login": "Login",
|
||||||
|
"Username": "Username",
|
||||||
|
"Password": "Password",
|
||||||
|
"Settings": "Settings",
|
||||||
|
"Logout": "Logout",
|
||||||
|
"Lowercase only": "Lowercase only",
|
||||||
|
"Convert to Compose": "Convert to Compose",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "active",
|
||||||
|
"exited": "exited",
|
||||||
|
"inactive": "inactive",
|
||||||
|
"Appearance": "Appearance",
|
||||||
|
"Security": "Security",
|
||||||
|
"About": "About",
|
||||||
|
"Allowed commands:": "Allowed commands:",
|
||||||
|
"Internal Networks": "Internal Networks",
|
||||||
|
"External Networks": "External Networks",
|
||||||
|
"No External Networks": "No External Networks"
|
||||||
}
|
}
|
||||||
|
|
94
frontend/src/lang/es.json
Normal file
94
frontend/src/lang/es.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Español",
|
||||||
|
"Create your admin account": "Crea tu cuenta de administrador",
|
||||||
|
"authIncorrectCreds": "Nombre de usuario o contraseña incorrectos.",
|
||||||
|
"PasswordsDoNotMatch": "Las contraseñas no coinciden.",
|
||||||
|
"Repeat Password": "Repetir Contraseña",
|
||||||
|
"Create": "Crear",
|
||||||
|
"signedInDisp": "Sesión iniciada como {0}",
|
||||||
|
"signedInDispDisabled": "Autenticación deshabilitada.",
|
||||||
|
"home": "Inicio",
|
||||||
|
"console": "Consola",
|
||||||
|
"registry": "Registro",
|
||||||
|
"compose": "Componer",
|
||||||
|
"addFirstStackMsg": "¡Compón tu primera pila!",
|
||||||
|
"stackName" : "Nombre de la Pila",
|
||||||
|
"deployStack": "Desplegar",
|
||||||
|
"deleteStack": "Eliminar",
|
||||||
|
"stopStack": "Detener",
|
||||||
|
"restartStack": "Reiniciar",
|
||||||
|
"updateStack": "Actualizar",
|
||||||
|
"startStack": "Iniciar",
|
||||||
|
"editStack": "Editar",
|
||||||
|
"discardStack": "Descartar",
|
||||||
|
"saveStackDraft": "Guardar",
|
||||||
|
"notAvailableShort" : "N/D",
|
||||||
|
"deleteStackMsg": "¿Estás seguro de que quieres eliminar esta pila?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Esta pila no está gestionada por Dockge.",
|
||||||
|
"primaryHostname": "Nombre de Host Primario",
|
||||||
|
"general": "General",
|
||||||
|
"container": "Contenedor | Contenedores",
|
||||||
|
"scanFolder": "Escanear Carpeta de Pilas",
|
||||||
|
"dockerImage": "Imagen",
|
||||||
|
"restartPolicyUnlessStopped": "A menos que se detenga",
|
||||||
|
"restartPolicyAlways": "Siempre",
|
||||||
|
"restartPolicyOnFailure": "En caso de fallo",
|
||||||
|
"restartPolicyNo": "No",
|
||||||
|
"environmentVariable": "Variable de Entorno | Variables de Entorno",
|
||||||
|
"restartPolicy": "Política de Reinicio",
|
||||||
|
"containerName": "Nombre del Contenedor",
|
||||||
|
"port": "Puerto | Puertos",
|
||||||
|
"volume": "Volumen | Volúmenes",
|
||||||
|
"network": "Red | Redes",
|
||||||
|
"dependsOn": "Dependencia del Contenedor | Dependencias del Contenedor",
|
||||||
|
"addListItem": "Agregar {0}",
|
||||||
|
"deleteContainer": "Eliminar",
|
||||||
|
"addContainer": "Agregar Contenedor",
|
||||||
|
"addNetwork": "Agregar Red",
|
||||||
|
"disableauth.message1": "¿Estás seguro de que deseas <strong>desactivar la autenticación</strong>?",
|
||||||
|
"disableauth.message2": "Está diseñado para escenarios <strong>donde pretendes implementar autenticación de terceros</strong> frente a Dockge, como Cloudflare Access, Authelia u otros mecanismos de autenticación.",
|
||||||
|
"passwordNotMatchMsg": "La contraseña repetida no coincide.",
|
||||||
|
"autoGet": "Obtener Automáticamente",
|
||||||
|
"add": "Agregar",
|
||||||
|
"Edit": "Editar",
|
||||||
|
"applyToYAML": "Aplicar a YAML",
|
||||||
|
"createExternalNetwork": "Crear",
|
||||||
|
"addInternalNetwork": "Agregar",
|
||||||
|
"Save": "Guardar",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Current User": "Usuario Actual",
|
||||||
|
"Change Password": "Cambiar Contraseña",
|
||||||
|
"Current Password": "Contraseña Actual",
|
||||||
|
"New Password": "Nueva Contraseña",
|
||||||
|
"Repeat New Password": "Repetir Nueva Contraseña",
|
||||||
|
"Update Password": "Actualizar Contraseña",
|
||||||
|
"Advanced": "Avanzado",
|
||||||
|
"Please use this option carefully!": "¡Por favor, usa esta opción con cuidado!",
|
||||||
|
"Enable Auth": "Habilitar Autenticación",
|
||||||
|
"Disable Auth": "Deshabilitar Autenticación",
|
||||||
|
"I understand, please disable": "Entiendo, por favor deshabilitar",
|
||||||
|
"Leave": "Salir",
|
||||||
|
"Frontend Version": "Versión del Frontend",
|
||||||
|
"Check Update On GitHub": "Comprobar Actualización en GitHub",
|
||||||
|
"Show update if available": "Mostrar actualización si está disponible",
|
||||||
|
"Also check beta release": "También verificar la versión beta",
|
||||||
|
"Remember me": "Recuérdame",
|
||||||
|
"Login": "Iniciar Sesión",
|
||||||
|
"Username": "Nombre de Usuario",
|
||||||
|
"Password": "Contraseña",
|
||||||
|
"Settings": "Configuración",
|
||||||
|
"Logout": "Cerrar Sesión",
|
||||||
|
"Lowercase only": "Solo minúsculas",
|
||||||
|
"Convert to Compose": "Convertir a Compose",
|
||||||
|
"Docker Run": "Ejecutar Docker",
|
||||||
|
"active": "activo",
|
||||||
|
"exited": "finalizado",
|
||||||
|
"inactive": "inactivo",
|
||||||
|
"Appearance": "Apariencia",
|
||||||
|
"Security": "Seguridad",
|
||||||
|
"About": "Acerca de",
|
||||||
|
"Allowed commands:": "Comandos permitidos:",
|
||||||
|
"Internal Networks": "Redes Internas",
|
||||||
|
"External Networks": "Redes Externas",
|
||||||
|
"No External Networks": "Sin Redes Externas"
|
||||||
|
}
|
94
frontend/src/lang/fr.json
Normal file
94
frontend/src/lang/fr.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Francais",
|
||||||
|
"Create your admin account": "Créez votre compte administrateur",
|
||||||
|
"authIncorrectCreds": "identifiant ou mot de passe incorrect.",
|
||||||
|
"Repeat Password": "Répéter le mot de passe",
|
||||||
|
"PasswordsDoNotMatch": "Les mots de passe ne correspondent pas.",
|
||||||
|
"Create": "Créer",
|
||||||
|
"signedInDisp": "Connecté en tant que {0}",
|
||||||
|
"signedInDispDisabled": "Authentification désactivée.",
|
||||||
|
"home": "Accueil",
|
||||||
|
"console": "Console",
|
||||||
|
"registry": "Registre",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Créez votre première pile!",
|
||||||
|
"stackName" : "Nom de la pile",
|
||||||
|
"deployStack": "Déployer",
|
||||||
|
"deleteStack": "Supprimer",
|
||||||
|
"stopStack": "Arrêter",
|
||||||
|
"restartStack": "Redémarrer",
|
||||||
|
"updateStack": "Mettre à jour",
|
||||||
|
"startStack": "Démarrer",
|
||||||
|
"editStack": "Modifier",
|
||||||
|
"discardStack": "Ignorer",
|
||||||
|
"saveStackDraft": "Sauvegarder",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Êtes-vous sûr de vouloir supprimer cette pile ?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Cette pile n'est pas gérée par Dockge.",
|
||||||
|
"primaryHostname": "Nom d'hôte principal",
|
||||||
|
"general": "Générale",
|
||||||
|
"container": "Conteneur | Conteneurs",
|
||||||
|
"scanFolder": "Analyser le dossier des piles",
|
||||||
|
"dockerImage": "Image",
|
||||||
|
"restartPolicyUnlessStopped": "Sauf arrêt",
|
||||||
|
"restartPolicyAlways": "Toujours",
|
||||||
|
"restartPolicyOnFailure": "En cas d'échec",
|
||||||
|
"restartPolicyNo": "Non",
|
||||||
|
"environmentVariable": "Variable d'environnement | Variables d'environnement",
|
||||||
|
"restartPolicy": "Politique de redémarrage",
|
||||||
|
"containerName": "Nom du conteneur",
|
||||||
|
"port": "Port | Ports",
|
||||||
|
"volume": "Volume | Volumes",
|
||||||
|
"network": "Réseau | Réseaux",
|
||||||
|
"dependsOn": "Dépendance du conteneur | Dépendances du conteneur",
|
||||||
|
"addListItem": "Ajouter {0}",
|
||||||
|
"deleteContainer": "Supprimer",
|
||||||
|
"addContainer": "Ajouter un conteneur",
|
||||||
|
"addNetwork": "Ajouter un réseau",
|
||||||
|
"disableauth.message1": "Voulez-vous vraiment <strong>désactiver l'authentification</strong> ?",
|
||||||
|
"disableauth.message2": "Il est conçu pour les scénarios <strong>dans lesquels vous avez l'intention d'implémenter une authentification tierce</strong> devant Dockge, comme Cloudflare Access, Authelia ou d'autres mécanismes d'authentification.",
|
||||||
|
"passwordNotMatchMsg": "Le mot de passe de confirmation ne correspond pas.",
|
||||||
|
"autoGet": "Obtention automatique",
|
||||||
|
"add": "Ajouter",
|
||||||
|
"Edit": "Modifier",
|
||||||
|
"applyToYAML": "Appliquer à YAML",
|
||||||
|
"createExternalNetwork": "Créer",
|
||||||
|
"addInternalNetwork": "Ajouter",
|
||||||
|
"Save": "Enregistrer",
|
||||||
|
"Language": "Langue",
|
||||||
|
"Current User": "Utilisateur Actuel",
|
||||||
|
"Change Password": "Changer le Mot de Passe",
|
||||||
|
"Current Password": "Mot de passe actuel",
|
||||||
|
"New Password": "Nouveau Mot de Passe",
|
||||||
|
"Repeat New Password": "Répéter le Nouveau Mot de Passe",
|
||||||
|
"Update Password": "Mettre à Jour le Mot de Passe",
|
||||||
|
"Advanced": "Avancé",
|
||||||
|
"Please use this option carefully!": "Veuillez utiliser cette option avec précaution !",
|
||||||
|
"Enable Auth": "Activer l'Authentification",
|
||||||
|
"Disable Auth": "Désactiver l'Authentification",
|
||||||
|
"I understand, please disable": "Je comprends, veuillez désactiver",
|
||||||
|
"Leave": "Quitter",
|
||||||
|
"Frontend Version": "Version Frontend",
|
||||||
|
"Check Update On GitHub": "Vérifier la Mise à Jour sur GitHub",
|
||||||
|
"Show update if available": "Afficher la mise à jour si disponible",
|
||||||
|
"Also check beta release": "Vérifier également la version bêta",
|
||||||
|
"Remember me": "Se souvenir de moi",
|
||||||
|
"Login": "Connexion",
|
||||||
|
"Username": "Nom d'utilisateur",
|
||||||
|
"Password": "Mot de Passe",
|
||||||
|
"Settings": "Paramètres",
|
||||||
|
"Logout": "Déconnexion",
|
||||||
|
"Lowercase only": "Minuscules uniquement",
|
||||||
|
"Convert to Compose": "Convertir en Compose",
|
||||||
|
"Docker Run": "Exécution Docker",
|
||||||
|
"active": "actif",
|
||||||
|
"exited": "arrêté",
|
||||||
|
"inactive": "inactif",
|
||||||
|
"Appearance": "Apparence",
|
||||||
|
"Security": "Sécurité",
|
||||||
|
"About": "À propos",
|
||||||
|
"Allowed commands:": "Commandes autorisées:",
|
||||||
|
"Internal Networks": "Réseaux Internes",
|
||||||
|
"External Networks": "Réseaux Externes",
|
||||||
|
"No External Networks": "Aucun Réseau Externe"
|
||||||
|
}
|
95
frontend/src/lang/it-IT.json
Normal file
95
frontend/src/lang/it-IT.json
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"languageName": "Italiano",
|
||||||
|
"Create your admin account": "Crea il tuo account amministratore",
|
||||||
|
"authIncorrectCreds": "Username e/o password errati.",
|
||||||
|
"PasswordsDoNotMatch": "Le password non corrispondono.",
|
||||||
|
"Repeat Password": "Ripetere la password",
|
||||||
|
"Create": "Crea",
|
||||||
|
"signedInDisp": "Autenticato come {0}",
|
||||||
|
"signedInDispDisabled": "Autenticazione disabilitata.",
|
||||||
|
"home": "Home",
|
||||||
|
"console": "Console",
|
||||||
|
"registry": "Registro",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Componi il tuo primo stack!",
|
||||||
|
"stackName" : "Nome dello stack",
|
||||||
|
"deployStack": "Deploy",
|
||||||
|
"deleteStack": "Cancella",
|
||||||
|
"stopStack": "Stop",
|
||||||
|
"restartStack": "Riavvia",
|
||||||
|
"updateStack": "Aggiorna",
|
||||||
|
"startStack": "Avvia",
|
||||||
|
"downStack": "Stop & Down",
|
||||||
|
"editStack": "Modifica",
|
||||||
|
"discardStack": "Annulla",
|
||||||
|
"saveStackDraft": "Salva",
|
||||||
|
"notAvailableShort" : "N/D",
|
||||||
|
"deleteStackMsg": "Sei sicuro di voler eliminare questo stack?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Questo stack non è gestito da Dockge.",
|
||||||
|
"primaryHostname": "Hostname primario",
|
||||||
|
"general": "Generale",
|
||||||
|
"container": "Container | Container",
|
||||||
|
"scanFolder": "Scansiona la cartella degli stack",
|
||||||
|
"dockerImage": "Immagine",
|
||||||
|
"restartPolicyUnlessStopped": "A meno che non venga fermato",
|
||||||
|
"restartPolicyAlways": "Sempre",
|
||||||
|
"restartPolicyOnFailure": "Quando fallisce",
|
||||||
|
"restartPolicyNo": "No",
|
||||||
|
"environmentVariable": "Variabile d'ambiente | Variabili d'ambiente",
|
||||||
|
"restartPolicy": "Politica di riavvio",
|
||||||
|
"containerName": "Nome del container",
|
||||||
|
"port": "Porta | Porte",
|
||||||
|
"volume": "Volume | Volumi",
|
||||||
|
"network": "Rete | Reti",
|
||||||
|
"dependsOn": "Dipendenza del container | Dipendenze del container",
|
||||||
|
"addListItem": "Aggiungi {0}",
|
||||||
|
"deleteContainer": "Elimina",
|
||||||
|
"addContainer": "Aggiungi container",
|
||||||
|
"addNetwork": "Aggiungi rete",
|
||||||
|
"disableauth.message1": "Sei sicuro di voler <strong>disabilitare l'autenticazione</strong>?",
|
||||||
|
"disableauth.message2": "È stato progettato per scenari <strong>in cui intendi implementare un'autenticazione di terze parti</strong> davanti a Dockge come ad esempio Cloudflare Access, Authelia o altri meccanismi di autenticazione.",
|
||||||
|
"passwordNotMatchMsg": "La password ripetuta non corrisponde.",
|
||||||
|
"autoGet": "Ottieni automaticamente",
|
||||||
|
"add": "Aggiungi",
|
||||||
|
"Edit": "Modifica",
|
||||||
|
"applyToYAML": "Applica al file YAML",
|
||||||
|
"createExternalNetwork": "Crea",
|
||||||
|
"addInternalNetwork": "Aggiungi",
|
||||||
|
"Save": "Salva",
|
||||||
|
"Language": "Lingua",
|
||||||
|
"Current User": "Utente corrente",
|
||||||
|
"Change Password": "Cambia la password",
|
||||||
|
"Current Password": "Password corrente",
|
||||||
|
"New Password": "Nuova password",
|
||||||
|
"Repeat New Password": "Ripeti la nuova password",
|
||||||
|
"Update Password": "Aggiornamento password",
|
||||||
|
"Advanced": "Avanzato",
|
||||||
|
"Please use this option carefully!": "Per favore usa questa opzione con cautela!",
|
||||||
|
"Enable Auth": "Abilita l'autenticazione",
|
||||||
|
"Disable Auth": "Disabilita l'autenticazione",
|
||||||
|
"I understand, please disable": "Lo capisco, disabilita",
|
||||||
|
"Leave": "Lascia",
|
||||||
|
"Frontend Version": "Versione del frontend",
|
||||||
|
"Check Update On GitHub": "Controlla la presenza di aggiornamenti su GitHub",
|
||||||
|
"Show update if available": "Mostra l'aggiornamento se è disponibile",
|
||||||
|
"Also check beta release": "Controlla anche le release in beta",
|
||||||
|
"Remember me": "Ricordami",
|
||||||
|
"Login": "Login",
|
||||||
|
"Username": "Username",
|
||||||
|
"Password": "Password",
|
||||||
|
"Settings": "Impostazioni",
|
||||||
|
"Logout": "Logout",
|
||||||
|
"Lowercase only": "Solo lettere minuscole",
|
||||||
|
"Convert to Compose": "Converti a Compose",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "attivo",
|
||||||
|
"exited": "uscito",
|
||||||
|
"inactive": "inattivo",
|
||||||
|
"Appearance": "Aspetto",
|
||||||
|
"Security": "Sicurezza",
|
||||||
|
"About": "Informazioni su",
|
||||||
|
"Allowed commands:": "Comandi permessi:",
|
||||||
|
"Internal Networks": "Reti interne",
|
||||||
|
"External Networks": "Reti esterne",
|
||||||
|
"No External Networks": "Nessuna rete esterna"
|
||||||
|
}
|
94
frontend/src/lang/ko-KR.json
Normal file
94
frontend/src/lang/ko-KR.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "한국어",
|
||||||
|
"Create your admin account": "관리자 계정 만들기",
|
||||||
|
"authIncorrectCreds": "사용자명 또는 비밀번호가 일치하지 않아요.",
|
||||||
|
"PasswordsDoNotMatch": "비밀번호가 일치하지 않아요.",
|
||||||
|
"Repeat Password": "비밀번호 재입력",
|
||||||
|
"Create": "생성",
|
||||||
|
"signedInDisp": "{0}(으)로 로그인됨",
|
||||||
|
"signedInDispDisabled": "인증 비활성화됨.",
|
||||||
|
"home": "홈",
|
||||||
|
"console": "콘솔",
|
||||||
|
"registry": "레지스트리",
|
||||||
|
"compose": "생성",
|
||||||
|
"addFirstStackMsg": "첫 번째 스택을 만들어 보세요!",
|
||||||
|
"stackName": "스택 이름",
|
||||||
|
"deployStack": "배포",
|
||||||
|
"deleteStack": "삭제",
|
||||||
|
"stopStack": "정지",
|
||||||
|
"restartStack": "재시작",
|
||||||
|
"updateStack": "업데이트",
|
||||||
|
"startStack": "시작",
|
||||||
|
"editStack": "수정",
|
||||||
|
"discardStack": "취소",
|
||||||
|
"saveStackDraft": "저장",
|
||||||
|
"notAvailableShort": "N/A",
|
||||||
|
"deleteStackMsg": "정말로 이 스택을 삭제하시겠습니까?",
|
||||||
|
"stackNotManagedByDockgeMsg": "이 스택은 Dockge에 의해 관리되지 않아요.",
|
||||||
|
"primaryHostname": "주 호스트명",
|
||||||
|
"general": "일반",
|
||||||
|
"container": "컨테이너",
|
||||||
|
"scanFolder": "스택 폴더 스캔",
|
||||||
|
"dockerImage": "이미지",
|
||||||
|
"restartPolicyUnlessStopped": "종료되기 전까지",
|
||||||
|
"restartPolicyAlways": "항상",
|
||||||
|
"restartPolicyOnFailure": "오류 발생 시",
|
||||||
|
"restartPolicyNo": "안 함",
|
||||||
|
"environmentVariable": "환경 변수",
|
||||||
|
"restartPolicy": "재시작 정책",
|
||||||
|
"containerName": "컨테이너 이름",
|
||||||
|
"port": "포트",
|
||||||
|
"volume": "볼륨",
|
||||||
|
"network": "네트워크",
|
||||||
|
"dependsOn": "컨테이너 의존성",
|
||||||
|
"addListItem": "{0} 추가",
|
||||||
|
"deleteContainer": "삭제",
|
||||||
|
"addContainer": "컨테이너 추가",
|
||||||
|
"addNetwork": "네트워크 추가",
|
||||||
|
"disableauth.message1": "정말로 <strong>인증을 비활성화</strong>하시겠습니까?",
|
||||||
|
"disableauth.message2": "이 기능은 Dockge 앞에 Cloudflare Access, Authelia 등과 같은 <strong>서드 파티 인증을 사용하려는 경우</strong>에 사용하기 위해서 만들어졌어요.",
|
||||||
|
"passwordNotMatchMsg": "비밀번호 재입력이 일치하지 않아요..",
|
||||||
|
"autoGet": "자동으로 가져오기",
|
||||||
|
"add": "추가",
|
||||||
|
"Edit": "수정",
|
||||||
|
"applyToYAML": "YAML에 적용",
|
||||||
|
"createExternalNetwork": "생성",
|
||||||
|
"addInternalNetwork": "추가",
|
||||||
|
"Save": "저장",
|
||||||
|
"Language": "언어",
|
||||||
|
"Current User": "현재 사용자",
|
||||||
|
"Change Password": "비밀번호 변경",
|
||||||
|
"Current Password": "현재 비밀번호",
|
||||||
|
"New Password": "새 비밀번호",
|
||||||
|
"Repeat New Password": "새 비밀번호 재입력",
|
||||||
|
"Update Password": "비밀번호 변경",
|
||||||
|
"Advanced": "고급",
|
||||||
|
"Please use this option carefully!": "이 설정은 신중히 사용하세요!",
|
||||||
|
"Enable Auth": "인증 활성화",
|
||||||
|
"Disable Auth": "인증 비활성화",
|
||||||
|
"I understand, please disable": "이해하고 있습니다. 비활성화해 주세요",
|
||||||
|
"Leave": "취소",
|
||||||
|
"Frontend Version": "프론트엔드 버전",
|
||||||
|
"Check Update On GitHub": "GitHub에서 업데이트 확인",
|
||||||
|
"Show update if available": "업데이트가 있을 때 표시",
|
||||||
|
"Also check beta release": "베타 버전도 확인",
|
||||||
|
"Remember me": "기억하기",
|
||||||
|
"Login": "로그인",
|
||||||
|
"Username": "사용자명",
|
||||||
|
"Password": "비밀번호",
|
||||||
|
"Settings": "설정",
|
||||||
|
"Logout": "로그아웃",
|
||||||
|
"Lowercase only": "소문자만",
|
||||||
|
"Convert to Compose": "Compose로 변환",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "활성",
|
||||||
|
"exited": "종료됨",
|
||||||
|
"inactive": "비활성",
|
||||||
|
"Appearance": "디스플레이",
|
||||||
|
"Security": "보안",
|
||||||
|
"About": "정보",
|
||||||
|
"Allowed commands:": "허용된 명령어:",
|
||||||
|
"Internal Networks": "내부 네트워크",
|
||||||
|
"External Networks": "외부 네트워크",
|
||||||
|
"No External Networks": "외부 네트워크 없음"
|
||||||
|
}
|
94
frontend/src/lang/pl-PL.json
Normal file
94
frontend/src/lang/pl-PL.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Polski",
|
||||||
|
"Create your admin account": "Utwórz konto administratora",
|
||||||
|
"authIncorrectCreds": "Nieprawidłowa nazwa użytkownika lub hasło.",
|
||||||
|
"PasswordsDoNotMatch": "Hasła nie pasują do siebie.",
|
||||||
|
"Repeat Password": "Powtórz hasło",
|
||||||
|
"Create": "Utwórz",
|
||||||
|
"signedInDisp": "Zalogowany jako {0}",
|
||||||
|
"signedInDispDisabled": "Autoryzacja wyłączona.",
|
||||||
|
"home": "Strona główna",
|
||||||
|
"console": "Konsola",
|
||||||
|
"registry": "Rejestr",
|
||||||
|
"compose": "Stwórz",
|
||||||
|
"addFirstStackMsg": "Stwórz swój pierwszy stos!",
|
||||||
|
"stackName" : "Nazwa stosu",
|
||||||
|
"deployStack": "Wdroż",
|
||||||
|
"deleteStack": "Usuń",
|
||||||
|
"stopStack": "Zatrzymaj",
|
||||||
|
"restartStack": "Uruchom ponownie",
|
||||||
|
"updateStack": "Aktualizuj",
|
||||||
|
"startStack": "Uruchom",
|
||||||
|
"editStack": "Edytuj",
|
||||||
|
"discardStack": "Odrzuć",
|
||||||
|
"saveStackDraft": "Zapisz",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Czy na pewno chcesz usunąć ten stos?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Ten stos nie jest zarządzany przez Dockge.",
|
||||||
|
"primaryHostname": "Podstawowa nazwa hosta",
|
||||||
|
"general": "Ogólne",
|
||||||
|
"container": "Kontener | Kontenery",
|
||||||
|
"scanFolder": "Skanuj folder ze stosami",
|
||||||
|
"dockerImage": "Obraz",
|
||||||
|
"restartPolicyUnlessStopped": "Jeśli nie zatrzymano",
|
||||||
|
"restartPolicyAlways": "Zawsze",
|
||||||
|
"restartPolicyOnFailure": "Po awarii",
|
||||||
|
"restartPolicyNo": "Nie restartuj",
|
||||||
|
"environmentVariable": "Zmienna środowiskowa | Zmienne środowiskowe",
|
||||||
|
"restartPolicy": "Polityka restartu",
|
||||||
|
"containerName": "Nazwa kontenera",
|
||||||
|
"port": "Port | Porty",
|
||||||
|
"volume": "Wolumin | Woluminy",
|
||||||
|
"network": "Sieć | Sieci",
|
||||||
|
"dependsOn": "Zależność kontenera | Zależności kontenera",
|
||||||
|
"addListItem": "Dodaj {0}",
|
||||||
|
"deleteContainer": "Usuń kontener",
|
||||||
|
"addContainer": "Dodaj kontener",
|
||||||
|
"addNetwork": "Dodaj sieć",
|
||||||
|
"disableauth.message1": "Czy na pewno chcesz <strong>wyłączyć uwierzytelnianie</strong>?",
|
||||||
|
"disableauth.message2": "Przeznaczone dla sytuacji, <strong>w których zamierzasz zaimplementować zewnętrzne mechanizmy uwierzytelniania</strong> przed Dockge, takie jak Cloudflare Access, Authelia lub inne.",
|
||||||
|
"passwordNotMatchMsg": "Hasła się nie zgadzają.",
|
||||||
|
"autoGet": "Automatyczne pobieranie",
|
||||||
|
"add": "Dodaj",
|
||||||
|
"Edit": "Edytuj",
|
||||||
|
"applyToYAML": "Zastosuj do YAML",
|
||||||
|
"createExternalNetwork": "Utwórz",
|
||||||
|
"addInternalNetwork": "Dodaj",
|
||||||
|
"Save": "Zapisz",
|
||||||
|
"Language": "Język",
|
||||||
|
"Current User": "Aktualny użytkownik",
|
||||||
|
"Change Password": "Zmień hasło",
|
||||||
|
"Current Password": "Aktualne hasło",
|
||||||
|
"New Password": "Nowe hasło",
|
||||||
|
"Repeat New Password": "Powtórz nowe hasło",
|
||||||
|
"Update Password": "Aktualizuj hasło",
|
||||||
|
"Advanced": "Zaawansowane",
|
||||||
|
"Please use this option carefully!": "Proszę używać tej opcji ostrożnie!",
|
||||||
|
"Enable Auth": "Włącz autoryzację",
|
||||||
|
"Disable Auth": "Wyłącz autoryzację",
|
||||||
|
"I understand, please disable": "Rozumiem, proszę wyłączyć",
|
||||||
|
"Leave": "Wyjdź",
|
||||||
|
"Frontend Version": "Wersja interfejsu graficznego",
|
||||||
|
"Check Update On GitHub": "Sprawdź dostępność aktualizacji na GitHub",
|
||||||
|
"Show update if available": "Pokaż aktualizacje, jeśli są dostępne",
|
||||||
|
"Also check beta release": "Sprawdź także wersje beta",
|
||||||
|
"Remember me": "Zapamiętaj mnie",
|
||||||
|
"Login": "Zaloguj się",
|
||||||
|
"Username": "Nazwa użytkownika",
|
||||||
|
"Password": "Hasło",
|
||||||
|
"Settings": "Ustawienia",
|
||||||
|
"Logout": "Wyloguj się",
|
||||||
|
"Lowercase only": "Tylko małe litery",
|
||||||
|
"Convert to Compose": "Przekształć na składnię Compose",
|
||||||
|
"Docker Run": "Uruchom za pomocą Dockera",
|
||||||
|
"active": "aktywny",
|
||||||
|
"exited": "wyłączony",
|
||||||
|
"inactive": "nieaktywny",
|
||||||
|
"Appearance": "Wygląd",
|
||||||
|
"Security": "Bezpieczeństwo",
|
||||||
|
"About": "O programie",
|
||||||
|
"Allowed commands:": "Dozwolone polecenia:",
|
||||||
|
"Internal Networks": "Sieci wewnętrzne",
|
||||||
|
"External Networks": "Sieci zewnętrzne",
|
||||||
|
"No External Networks": "Brak sieci zewnętrznych"
|
||||||
|
}
|
94
frontend/src/lang/pt-BR.json
Normal file
94
frontend/src/lang/pt-BR.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Português-Brasil",
|
||||||
|
"Create your admin account": "Crie sua conta de administrador",
|
||||||
|
"authIncorrectCreds": "Nome de usuário ou senha incorretos.",
|
||||||
|
"PasswordsDoNotMatch": "As senhas não correspondem.",
|
||||||
|
"Repeat Password": "Repetir a senha",
|
||||||
|
"Create": "Criar",
|
||||||
|
"signedInDisp": "Logado como {0}",
|
||||||
|
"signedInDispDisabled": "Autenticação desativada.",
|
||||||
|
"home": "Início",
|
||||||
|
"console": "Console",
|
||||||
|
"registry": "Registro",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Crie sua primeira stack!",
|
||||||
|
"stackName" : "Nome da stack",
|
||||||
|
"deployStack": "Deploy",
|
||||||
|
"deleteStack": "Excluir",
|
||||||
|
"stopStack": "Parar",
|
||||||
|
"restartStack": "Reiniciar",
|
||||||
|
"updateStack": "Atualizar",
|
||||||
|
"startStack": "Iniciar",
|
||||||
|
"editStack": "Editar",
|
||||||
|
"discardStack": "Descartar",
|
||||||
|
"saveStackDraft": "Salvar",
|
||||||
|
"notAvailableShort" : "N/D",
|
||||||
|
"deleteStackMsg": "Tem certeza que deseja excluir esta stack?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Esta stack não é gerenciada pelo Dockge.",
|
||||||
|
"primaryHostname": "Nome do Host Primário",
|
||||||
|
"general": "Geral",
|
||||||
|
"container": "Contêiner | Contêineres",
|
||||||
|
"scanFolder": "Pesquisar na pasta de stacks",
|
||||||
|
"dockerImage": "Imagem",
|
||||||
|
"restartPolicyUnlessStopped": "A menos que seja parado",
|
||||||
|
"restartPolicyAlways": "Sempre",
|
||||||
|
"restartPolicyOnFailure": "Em caso de falha",
|
||||||
|
"restartPolicyNo": "Não",
|
||||||
|
"environmentVariable": "Variável de ambiente | Variáveis de ambiente",
|
||||||
|
"restartPolicy": "Política de reinicialização",
|
||||||
|
"containerName": "Nome do contêiner",
|
||||||
|
"port": "Porta | Portas",
|
||||||
|
"volume": "Volume | Volumes",
|
||||||
|
"network": "Rede | Redes",
|
||||||
|
"dependsOn": "Dependência do contêiner | Dependências do contêiner",
|
||||||
|
"addListItem": "Adicionar {0}",
|
||||||
|
"deleteContainer": "Excluir",
|
||||||
|
"addContainer": "Adicionar contêiner",
|
||||||
|
"addNetwork": "Adicionar rede",
|
||||||
|
"disableauth.message1": "Tem certeza que deseja <strong>desativar a autenticação</strong>?",
|
||||||
|
"disableauth.message2": "Isso foi projetado para ambientes <strong>onde você pretende implementar autenticação de terceiros</strong> no Dockge, como Cloudflare Access, Authelia entre outros mecanismos de autenticação.",
|
||||||
|
"passwordNotMatchMsg": "A senha repetida não corresponde.",
|
||||||
|
"autoGet": "Obter automaticamente",
|
||||||
|
"add": "Adicionar",
|
||||||
|
"Edit": "Editar",
|
||||||
|
"applyToYAML": "Aplicar ao YAML",
|
||||||
|
"createExternalNetwork": "Criar",
|
||||||
|
"addInternalNetwork": "Adicionar",
|
||||||
|
"Save": "Salvar",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Current User": "Usuário atual",
|
||||||
|
"Change Password": "Alterar senha",
|
||||||
|
"Current Password": "Senha atual",
|
||||||
|
"New Password": "Nova senha",
|
||||||
|
"Repeat New Password": "Repetir nova senha",
|
||||||
|
"Update Password": "Atualizar senha",
|
||||||
|
"Advanced": "Avançado",
|
||||||
|
"Please use this option carefully!": "Por favor, use esta opção com atenção!",
|
||||||
|
"Enable Auth": "Habilitar autenticação",
|
||||||
|
"Disable Auth": "Desabilitar autenticação",
|
||||||
|
"I understand, please disable": "Entendido, por favor desabilitar",
|
||||||
|
"Leave": "Sair",
|
||||||
|
"Frontend Version": "Versão da interface",
|
||||||
|
"Check Update On GitHub": "Verificar atualização no GitHub",
|
||||||
|
"Show update if available": "Mostrar atualização se disponível",
|
||||||
|
"Also check beta release": "Também verificar versão beta",
|
||||||
|
"Remember me": "Lembrar-me",
|
||||||
|
"Login": "Entrar",
|
||||||
|
"Username": "Nome de usuário",
|
||||||
|
"Password": "Senha",
|
||||||
|
"Settings": "Configurações",
|
||||||
|
"Logout": "Sair",
|
||||||
|
"Lowercase only": "Somente minúsculas",
|
||||||
|
"Convert to Compose": "Converter para compose",
|
||||||
|
"Docker Run": "Executar Docker",
|
||||||
|
"active": "ativo",
|
||||||
|
"exited": "encerrado",
|
||||||
|
"inactive": "inativo",
|
||||||
|
"Appearance": "Aparência",
|
||||||
|
"Security": "Segurança",
|
||||||
|
"About": "Sobre",
|
||||||
|
"Allowed commands:": "Comandos permitidos:",
|
||||||
|
"Internal Networks": "Redes internas",
|
||||||
|
"External Networks": "Redes externas",
|
||||||
|
"No External Networks": "Sem redes externas"
|
||||||
|
}
|
94
frontend/src/lang/pt.json
Normal file
94
frontend/src/lang/pt.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Português",
|
||||||
|
"Create your admin account": "Crie sua conta de administrador",
|
||||||
|
"authIncorrectCreds": "Nome de usuário ou senha incorretos.",
|
||||||
|
"PasswordsDoNotMatch": "As senhas não coincidem.",
|
||||||
|
"Repeat Password": "Repetir Senha",
|
||||||
|
"Create": "Criar",
|
||||||
|
"signedInDisp": "Logado como {0}",
|
||||||
|
"signedInDispDisabled": "Autenticação desativada.",
|
||||||
|
"home": "Início",
|
||||||
|
"console": "Console",
|
||||||
|
"registry": "Registro",
|
||||||
|
"compose": "Compor",
|
||||||
|
"addFirstStackMsg": "Componha sua primeira pilha!",
|
||||||
|
"stackName" : "Nome da Pilha",
|
||||||
|
"deployStack": "Implantar",
|
||||||
|
"deleteStack": "Excluir",
|
||||||
|
"stopStack": "Parar",
|
||||||
|
"restartStack": "Reiniciar",
|
||||||
|
"updateStack": "Atualizar",
|
||||||
|
"startStack": "Iniciar",
|
||||||
|
"editStack": "Editar",
|
||||||
|
"discardStack": "Descartar",
|
||||||
|
"saveStackDraft": "Salvar",
|
||||||
|
"notAvailableShort" : "N/D",
|
||||||
|
"deleteStackMsg": "Tem certeza de que deseja excluir esta pilha?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Esta pilha não é gerenciada pelo Dockge.",
|
||||||
|
"primaryHostname": "Nome do Host Primário",
|
||||||
|
"general": "Geral",
|
||||||
|
"container": "Contêiner | Contêineres",
|
||||||
|
"scanFolder": "Digitalizar Pasta de Pilhas",
|
||||||
|
"dockerImage": "Imagem",
|
||||||
|
"restartPolicyUnlessStopped": "A menos que seja parado",
|
||||||
|
"restartPolicyAlways": "Sempre",
|
||||||
|
"restartPolicyOnFailure": "Em caso de falha",
|
||||||
|
"restartPolicyNo": "Não",
|
||||||
|
"environmentVariable": "Variável de Ambiente | Variáveis de Ambiente",
|
||||||
|
"restartPolicy": "Política de Reinicialização",
|
||||||
|
"containerName": "Nome do Contêiner",
|
||||||
|
"port": "Porta | Portas",
|
||||||
|
"volume": "Volume | Volumes",
|
||||||
|
"network": "Rede | Redes",
|
||||||
|
"dependsOn": "Dependência do Contêiner | Dependências do Contêiner",
|
||||||
|
"addListItem": "Adicionar {0}",
|
||||||
|
"deleteContainer": "Excluir",
|
||||||
|
"addContainer": "Adicionar Contêiner",
|
||||||
|
"addNetwork": "Adicionar Rede",
|
||||||
|
"disableauth.message1": "Tem certeza de que deseja <strong>desativar a autenticação</strong>?",
|
||||||
|
"disableauth.message2": "Isso é projetado para cenários <strong>onde você pretende implementar autenticação de terceiros</strong> no Dockge, como Cloudflare Access, Authelia ou outros mecanismos de autenticação.",
|
||||||
|
"passwordNotMatchMsg": "A senha repetida não coincide.",
|
||||||
|
"autoGet": "Obter Automaticamente",
|
||||||
|
"add": "Adicionar",
|
||||||
|
"Edit": "Editar",
|
||||||
|
"applyToYAML": "Aplicar ao YAML",
|
||||||
|
"createExternalNetwork": "Criar",
|
||||||
|
"addInternalNetwork": "Adicionar",
|
||||||
|
"Save": "Salvar",
|
||||||
|
"Language": "Idioma",
|
||||||
|
"Current User": "Usuário Atual",
|
||||||
|
"Change Password": "Alterar Senha",
|
||||||
|
"Current Password": "Senha Atual",
|
||||||
|
"New Password": "Nova Senha",
|
||||||
|
"Repeat New Password": "Repetir Nova Senha",
|
||||||
|
"Update Password": "Atualizar Senha",
|
||||||
|
"Advanced": "Avançado",
|
||||||
|
"Please use this option carefully!": "Por favor, use esta opção com cuidado!",
|
||||||
|
"Enable Auth": "Habilitar Autenticação",
|
||||||
|
"Disable Auth": "Desabilitar Autenticação",
|
||||||
|
"I understand, please disable": "Entendo, por favor desabilitar",
|
||||||
|
"Leave": "Sair",
|
||||||
|
"Frontend Version": "Versão da Interface",
|
||||||
|
"Check Update On GitHub": "Verificar Atualização no GitHub",
|
||||||
|
"Show update if available": "Mostrar atualização se disponível",
|
||||||
|
"Also check beta release": "Também verificar versão beta",
|
||||||
|
"Remember me": "Lembrar-me",
|
||||||
|
"Login": "Entrar",
|
||||||
|
"Username": "Nome de Usuário",
|
||||||
|
"Password": "Senha",
|
||||||
|
"Settings": "Configurações",
|
||||||
|
"Logout": "Sair",
|
||||||
|
"Lowercase only": "Somente minúsculas",
|
||||||
|
"Convert to Compose": "Converter para Compose",
|
||||||
|
"Docker Run": "Executar Docker",
|
||||||
|
"active": "ativo",
|
||||||
|
"exited": "encerrado",
|
||||||
|
"inactive": "inativo",
|
||||||
|
"Appearance": "Aparência",
|
||||||
|
"Security": "Segurança",
|
||||||
|
"About": "Sobre",
|
||||||
|
"Allowed commands:": "Comandos permitidos:",
|
||||||
|
"Internal Networks": "Redes Internas",
|
||||||
|
"External Networks": "Redes Externas",
|
||||||
|
"No External Networks": "Sem Redes Externas"
|
||||||
|
}
|
94
frontend/src/lang/ru.json
Normal file
94
frontend/src/lang/ru.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Русский",
|
||||||
|
"Create your admin account": "Создайте учетку администратора",
|
||||||
|
"authIncorrectCreds": "Неверный логин или пароль.",
|
||||||
|
"PasswordsDoNotMatch": "Пароль не совпадает.",
|
||||||
|
"Repeat Password": "Повторите пароль",
|
||||||
|
"Create": "Создать",
|
||||||
|
"signedInDisp": "Авторизлван как {0}",
|
||||||
|
"signedInDispDisabled": "Авторизация выключена.",
|
||||||
|
"home": "Главная",
|
||||||
|
"console": "Консоль",
|
||||||
|
"registry": "Registry",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Создайте свой первый стек!",
|
||||||
|
"stackName" : "Имя стека",
|
||||||
|
"deployStack": "Развернуть",
|
||||||
|
"deleteStack": "Удалить",
|
||||||
|
"stopStack": "Остановить",
|
||||||
|
"restartStack": "Перезапустить",
|
||||||
|
"updateStack": "Обновить",
|
||||||
|
"startStack": "Запустить",
|
||||||
|
"editStack": "Изменить",
|
||||||
|
"discardStack": "Отменить",
|
||||||
|
"saveStackDraft": "Сохранить",
|
||||||
|
"notAvailableShort" : "Н/Д",
|
||||||
|
"deleteStackMsg": "Вы уверены что хотите удалить этот стек?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Данный стек не обслуживается Dockge.",
|
||||||
|
"primaryHostname": "Имя хоста",
|
||||||
|
"general": "Главное",
|
||||||
|
"container": "Контейнер | Контейнеры",
|
||||||
|
"scanFolder": "Сканировать папку стеков",
|
||||||
|
"dockerImage": "Образ",
|
||||||
|
"restartPolicyUnlessStopped": "Пока не будет остановлен",
|
||||||
|
"restartPolicyAlways": "Всегда",
|
||||||
|
"restartPolicyOnFailure": "При падении",
|
||||||
|
"restartPolicyNo": "Никогда",
|
||||||
|
"environmentVariable": "Переменная окружения | Переменные окружения",
|
||||||
|
"restartPolicy": "Политика рестарта",
|
||||||
|
"containerName": "Имя контейнера",
|
||||||
|
"port": "Порт | Порты",
|
||||||
|
"volume": "Хранилище | Хранилища",
|
||||||
|
"network": "Сеть | Сети",
|
||||||
|
"dependsOn": "Зависимость контейнера | Зависимости контейнера",
|
||||||
|
"addListItem": "Добавить {0}",
|
||||||
|
"deleteContainer": "Удалить",
|
||||||
|
"addContainer": "Добавить Контейнер",
|
||||||
|
"addNetwork": "Добавить Сеть",
|
||||||
|
"disableauth.message1": "Вы уверены что хотите <strong>выключить авторизацию</strong>?",
|
||||||
|
"disableauth.message2": "Он предназначен для сценариев, <strong>где вы собираетесь реализовать стороннюю аутентификацию</strong> перед Dockge, например Cloudflare Access, Authelia или другие механизмы аутентификации.",
|
||||||
|
"passwordNotMatchMsg": "Повторный пароль не совпадает.",
|
||||||
|
"autoGet": "Auto Get",
|
||||||
|
"add": "Добавить",
|
||||||
|
"Edit": "Изменить",
|
||||||
|
"applyToYAML": "Применить к YAML",
|
||||||
|
"createExternalNetwork": "Создать",
|
||||||
|
"addInternalNetwork": "Добавить",
|
||||||
|
"Save": "Сохранить",
|
||||||
|
"Language": "Язык",
|
||||||
|
"Current User": "Текущий пользователь",
|
||||||
|
"Change Password": "Изменить пароль",
|
||||||
|
"Current Password": "Текущий пароль",
|
||||||
|
"New Password": "Новый пароль",
|
||||||
|
"Repeat New Password": "Повторите новый пароль",
|
||||||
|
"Update Password": "Обновить пароль",
|
||||||
|
"Advanced": "Продвинутые опции",
|
||||||
|
"Please use this option carefully!": "Пожалуйста, используйте эту опцию осторожно!",
|
||||||
|
"Enable Auth": "Включить аутентификацию",
|
||||||
|
"Disable Auth": "Отключить аутентификацию",
|
||||||
|
"I understand, please disable": "Я понимаю, пожалуйста, отключите",
|
||||||
|
"Leave": "Покинуть",
|
||||||
|
"Frontend Version": "Версия внешнего интерфейса",
|
||||||
|
"Check Update On GitHub": "Проверьте обновление на GitHub",
|
||||||
|
"Show update if available": "Показать обновление, если оно доступно",
|
||||||
|
"Also check beta release": "Также проверьте бета-версию",
|
||||||
|
"Remember me": "Запомнить меня",
|
||||||
|
"Login": "Логин",
|
||||||
|
"Username": "Имя пользователя",
|
||||||
|
"Password": "Пароль",
|
||||||
|
"Settings": "Настройки",
|
||||||
|
"Logout": "Выйти",
|
||||||
|
"Lowercase only": "Только нижний регистр",
|
||||||
|
"Convert to Compose": "Преобразовать вCompose",
|
||||||
|
"Docker Run": "Запустить Docker",
|
||||||
|
"active": "активный",
|
||||||
|
"exited": "завершенный",
|
||||||
|
"inactive": "неактинвый",
|
||||||
|
"Appearance": "Внешний вид",
|
||||||
|
"Security": "Безопасность",
|
||||||
|
"About": "О продукте",
|
||||||
|
"Allowed commands:": "Разрешенные команды:",
|
||||||
|
"Internal Networks": "Внутренние сети",
|
||||||
|
"External Networks": "Внешние сети",
|
||||||
|
"No External Networks": "Нет внешних сетей"
|
||||||
|
}
|
94
frontend/src/lang/sl.json
Normal file
94
frontend/src/lang/sl.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Slovenščina",
|
||||||
|
"Create your admin account": "Ustvarite svoj skrbniški račun",
|
||||||
|
"authIncorrectCreds": "Napačno uporabniško ime ali geslo.",
|
||||||
|
"PasswordsDoNotMatch": "Gesli se ne ujemata.",
|
||||||
|
"Repeat Password": "Ponovi geslo",
|
||||||
|
"Create": "Ustvari",
|
||||||
|
"signedInDisp": "Prijavljeni kot {0}",
|
||||||
|
"signedInDispDisabled": "Preverjanje pristnosti onemogočeno.",
|
||||||
|
"home": "Domov",
|
||||||
|
"console": "Konzola",
|
||||||
|
"registry": "Register",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Ustvarite svoj prvi Stack!",
|
||||||
|
"stackName": "Ime Stack-a",
|
||||||
|
"deployStack": "Razporedi",
|
||||||
|
"deleteStack": "Izbriši",
|
||||||
|
"stopStack": "Ustavi",
|
||||||
|
"restartStack": "Ponovni zagon",
|
||||||
|
"updateStack": "Posodobi",
|
||||||
|
"startStack": "Zaženi",
|
||||||
|
"editStack": "Uredi",
|
||||||
|
"discardStack": "Zavrzi",
|
||||||
|
"saveStackDraft": "Shrani",
|
||||||
|
"notAvailableShort": "Ni na voljo",
|
||||||
|
"deleteStackMsg": "Ste prepričani, da želite izbrisati ta Stack?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Ta Stack ni upravljan s strani Dockge.",
|
||||||
|
"primaryHostname": "Osnovno gostiteljsko ime",
|
||||||
|
"general": "Splošno",
|
||||||
|
"container": "Kontejner | Kontejnerji",
|
||||||
|
"scanFolder": "Preglej Stack mapo",
|
||||||
|
"dockerImage": "Slika",
|
||||||
|
"restartPolicyUnlessStopped": "Razen ko je zaustavljeno",
|
||||||
|
"restartPolicyAlways": "Vedno",
|
||||||
|
"restartPolicyOnFailure": "Ob napaki",
|
||||||
|
"restartPolicyNo": "Ne",
|
||||||
|
"environmentVariable": "Okoljska spremenljivka | Okoljske spremenljivke",
|
||||||
|
"restartPolicy": "Politika ponovnega zagona",
|
||||||
|
"containerName": "Ime kontejnerja",
|
||||||
|
"port": "Vrata | Vrata",
|
||||||
|
"volume": "Zvezek | Zvezki",
|
||||||
|
"network": "Omrežje | Omrežja",
|
||||||
|
"dependsOn": "Odvisnost kontejnerja | Odvisnosti kontejnerjev",
|
||||||
|
"addListItem": "Dodaj {0}",
|
||||||
|
"deleteContainer": "Izbriši",
|
||||||
|
"addContainer": "Dodaj kontejner",
|
||||||
|
"addNetwork": "Dodaj omrežje",
|
||||||
|
"disableauth.message1": "Ste prepričani, da želite <strong>onemogočiti overjanje</strong>?",
|
||||||
|
"disableauth.message2": "Namerno je zasnovano za scenarije, <strong>kjer nameravate izvajati avtentikacijo tretjih oseb</strong> pred Dockge, kot so Cloudflare Access, Authelia ali druge avtentikacijske mehanizme.",
|
||||||
|
"passwordNotMatchMsg": "Ponovljeno geslo se ne ujema.",
|
||||||
|
"autoGet": "Samodejno pridobi",
|
||||||
|
"add": "Dodaj",
|
||||||
|
"Edit": "Uredi",
|
||||||
|
"applyToYAML": "Uporabi za YAML",
|
||||||
|
"createExternalNetwork": "Ustvari",
|
||||||
|
"addInternalNetwork": "Dodaj",
|
||||||
|
"Save": "Shrani",
|
||||||
|
"Language": "Jezik",
|
||||||
|
"Current User": "Trenutni uporabnik",
|
||||||
|
"Change Password": "Spremeni geslo",
|
||||||
|
"Current Password": "Trenutno geslo",
|
||||||
|
"New Password": "Novo geslo",
|
||||||
|
"Repeat New Password": "Ponovi novo geslo",
|
||||||
|
"Update Password": "Posodobi geslo",
|
||||||
|
"Advanced": "Napredno",
|
||||||
|
"Please use this option carefully!": "Prosimo, uporabite to možnost previdno!",
|
||||||
|
"Enable Auth": "Omogoči overjanje",
|
||||||
|
"Disable Auth": "Onemogoči overjanje",
|
||||||
|
"I understand, please disable": "Razumem, prosim onemogočite",
|
||||||
|
"Leave": "Zapusti",
|
||||||
|
"Frontend Version": "Različica vmesnika",
|
||||||
|
"Check Update On GitHub": "Preveri posodobitve na GitHubu",
|
||||||
|
"Show update if available": "Prikaži posodobitve, če so na voljo",
|
||||||
|
"Also check beta release": "Preveri tudi beta izdaje",
|
||||||
|
"Remember me": "Zapomni si me",
|
||||||
|
"Login": "Prijava",
|
||||||
|
"Username": "Uporabniško ime",
|
||||||
|
"Password": "Geslo",
|
||||||
|
"Settings": "Nastavitve",
|
||||||
|
"Logout": "Odjava",
|
||||||
|
"Lowercase only": "Samo male črke",
|
||||||
|
"Convert to Compose": "Pretvori v Compose",
|
||||||
|
"Docker Run": "Zagon Dockerja",
|
||||||
|
"active": "aktivno",
|
||||||
|
"exited": "izklopljeno",
|
||||||
|
"inactive": "neaktivno",
|
||||||
|
"Appearance": "Videz",
|
||||||
|
"Security": "Varnost",
|
||||||
|
"About": "O nas",
|
||||||
|
"Allowed commands:": "Dovoljeni ukazi:",
|
||||||
|
"Internal Networks": "Notranja omrežja",
|
||||||
|
"External Networks": "Zunanja omrežja",
|
||||||
|
"No External Networks": "Ni zunanjih omrežij"
|
||||||
|
}
|
95
frontend/src/lang/sv-SE.json
Normal file
95
frontend/src/lang/sv-SE.json
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"languageName": "Svenska",
|
||||||
|
"Create your admin account": "Skapa ditt Admin-konto.",
|
||||||
|
"authIncorrectCreds": "Fel användarnamn eller lösenord.",
|
||||||
|
"PasswordsDoNotMatch": "Lösenorden matchar inte.",
|
||||||
|
"Repeat Password": "Repetera lösenord",
|
||||||
|
"Create": "Skapa",
|
||||||
|
"signedInDisp": "Inloggad som {0}",
|
||||||
|
"signedInDispDisabled": "Auth inaktiverad.",
|
||||||
|
"home": "Hem",
|
||||||
|
"console": "Konsol",
|
||||||
|
"registry": "Register",
|
||||||
|
"compose": "Komponera",
|
||||||
|
"addFirstStackMsg": "Komponera din första stack!",
|
||||||
|
"stackName" : "Stacknamn",
|
||||||
|
"deployStack": "Distribuera",
|
||||||
|
"deleteStack": "Radera",
|
||||||
|
"stopStack": "Stop",
|
||||||
|
"restartStack": "Starta om",
|
||||||
|
"updateStack": "Uppdatera",
|
||||||
|
"startStack": "Starta",
|
||||||
|
"downStack": "Stop & Ner",
|
||||||
|
"editStack": "Redigera",
|
||||||
|
"discardStack": "Kasta",
|
||||||
|
"saveStackDraft": "Spara",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Är du säker på att du vill radera stacken?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Denna stacken hanteras inte av Dockge.",
|
||||||
|
"primaryHostname": "Primärt värdnamn",
|
||||||
|
"general": "Allmän",
|
||||||
|
"container": "Container | Containrar",
|
||||||
|
"scanFolder": "Scanna Stackfolder",
|
||||||
|
"dockerImage": "Bild",
|
||||||
|
"restartPolicyUnlessStopped": "Om inte stoppas",
|
||||||
|
"restartPolicyAlways": "Alltid",
|
||||||
|
"restartPolicyOnFailure": "Vid Misslyckande",
|
||||||
|
"restartPolicyNo": "Nej",
|
||||||
|
"environmentVariable": "Miljövariabel | Miljövariabler",
|
||||||
|
"restartPolicy": "Omstartspolicy",
|
||||||
|
"containerName": "Containernamn",
|
||||||
|
"port": "Port | Portar",
|
||||||
|
"volume": "Volym | Volymer",
|
||||||
|
"network": "Nätverk | Nätverk",
|
||||||
|
"dependsOn": "Containerberoende | Containerberoenden",
|
||||||
|
"addListItem": "Lägg till {0}",
|
||||||
|
"deleteContainer": "Radera",
|
||||||
|
"addContainer": "Lägg till Container",
|
||||||
|
"addNetwork": "Lägg till Nätverk",
|
||||||
|
"disableauth.message1": "Är du säker på att du vill <strong>inaktivera autentisering</strong>?",
|
||||||
|
"disableauth.message2": "Det är designat för senarion <stong>när du ska implementera tredjeparts autentisering</strong> framör Dockge som Cloudflare Access, Authelia eller andra autentiseringsmekanismer.",
|
||||||
|
"passwordNotMatchMsg": "Det upprepade lösenordet matchar inte",
|
||||||
|
"autoGet": "Auto Hämta",
|
||||||
|
"add": "Lägg till",
|
||||||
|
"Edit": "Redigera",
|
||||||
|
"applyToYAML": "Lägg till i YAML",
|
||||||
|
"createExternalNetwork": "Skapa",
|
||||||
|
"addInternalNetwork": "Lägg till",
|
||||||
|
"Save": "Spara",
|
||||||
|
"Language": "Språk",
|
||||||
|
"Current User": "Nuvarande användaren",
|
||||||
|
"Change Password": "Byt lösenord",
|
||||||
|
"Current Password": "Nuvarande lösenord",
|
||||||
|
"New Password": "Nytt lösenord",
|
||||||
|
"Repeat New Password": "Upprepa nytt lösenord",
|
||||||
|
"Update Password": "Uppdatera lösenord",
|
||||||
|
"Advanced": "Avancerat",
|
||||||
|
"Please use this option carefully!": "Använd detta alternativ försiktigt!",
|
||||||
|
"Enable Auth": "Aktivera Auth",
|
||||||
|
"Disable Auth": "Avaktivera Auth",
|
||||||
|
"I understand, please disable": "Jag förstår, vänligen inaktivera",
|
||||||
|
"Leave": "Lämna",
|
||||||
|
"Frontend Version": "Frontendversion",
|
||||||
|
"Check Update On GitHub": "Kontrollera Uppdatering på GitHub",
|
||||||
|
"Show update if available": "Visa uppdatering om tillgänglig",
|
||||||
|
"Also check beta release": "Kontrollera även betaversionen",
|
||||||
|
"Remember me": "Kom ihåg mig",
|
||||||
|
"Login": "Logga in",
|
||||||
|
"Username": "Användarnamn",
|
||||||
|
"Password": "Lösenord",
|
||||||
|
"Settings": "Inställningar",
|
||||||
|
"Logout": "Logga ut",
|
||||||
|
"Lowercase only": "Endast små tecken",
|
||||||
|
"Convert to Compose": "Omvandla till Compose",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "aktiv",
|
||||||
|
"exited": "avslutad",
|
||||||
|
"inactive": "inaktiv",
|
||||||
|
"Appearance": "Utseende",
|
||||||
|
"Security": "Säkerhet",
|
||||||
|
"About": "Om",
|
||||||
|
"Allowed commands:": "Tillåtna kommandon:",
|
||||||
|
"Internal Networks": "Interna Nätverk",
|
||||||
|
"External Networks": "Externa Nätverk",
|
||||||
|
"No External Networks": "Inga Externa Nätverk"
|
||||||
|
}
|
95
frontend/src/lang/th.json
Normal file
95
frontend/src/lang/th.json
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
"languageName": "ไทย",
|
||||||
|
"Create your admin account": "สร้างบัญชีผู้ดูแลระบบของคุณ",
|
||||||
|
"authIncorrectCreds": "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง",
|
||||||
|
"PasswordsDoNotMatch": "รหัสผ่านไม่ตรงกัน",
|
||||||
|
"Repeat Password": "ยืนยันรหัสผ่าน",
|
||||||
|
"Create": "สร้าง",
|
||||||
|
"signedInDisp": "ลงชื่อเข้าใช้ในชื่อ {0}",
|
||||||
|
"signedInDispDisabled": "ปิดใช้งาน Auth",
|
||||||
|
"home": "หน้าหลักe",
|
||||||
|
"console": "คอนโซล",
|
||||||
|
"registry": "Registry",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "Compose stack แรกของคุณ",
|
||||||
|
"stackName": "ชื่อ Stack",
|
||||||
|
"deployStack": "ปรับใช้",
|
||||||
|
"deleteStack": "ลบ",
|
||||||
|
"stopStack": "หยุด",
|
||||||
|
"restartStack": "เริ่มใหม่",
|
||||||
|
"updateStack": "อัปเดต",
|
||||||
|
"startStack": "เริ่มต้น",
|
||||||
|
"downStack": "หยุดและปิด",
|
||||||
|
"editStack": "แก้ไข",
|
||||||
|
"discardStack": "ยกเลิก",
|
||||||
|
"saveStackDraft": "บันทึก",
|
||||||
|
"notAvailableShort": "N/A",
|
||||||
|
"deleteStackMsg": "คุณแน่ใจหรือไม่ว่าต้องการลบ stack นี้",
|
||||||
|
"stackNotManagedByDockgeMsg": "stack นี้ไม่ได้รับการจัดการโดย Dockge",
|
||||||
|
"primaryHostname": "ชื่อโฮสต์หลัก",
|
||||||
|
"general": "ทั่วไป",
|
||||||
|
"container": "Container | Containers",
|
||||||
|
"scanFolder": "สแกนโฟลเดอร์ Stacks",
|
||||||
|
"dockerImage": "Image",
|
||||||
|
"restartPolicyUnlessStopped": "Unless Stopped",
|
||||||
|
"restartPolicyAlways": "Always",
|
||||||
|
"restartPolicyOnFailure": "On Failure",
|
||||||
|
"restartPolicyNo": "No",
|
||||||
|
"environmentVariable": "Environment Variable | Environment Variables",
|
||||||
|
"restartPolicy": "เริ่มต้น Policy ใหม่",
|
||||||
|
"containerName": "ชื่อ Container",
|
||||||
|
"port": "พอร์ต | พอร์ต",
|
||||||
|
"volume": "ปริมาณ | ปริมาณ",
|
||||||
|
"network": "เครือข่าย | เครือข่าย",
|
||||||
|
"dependsOn": "Container Dependency | Container Dependencies",
|
||||||
|
"addListItem": "เพิ่ม {0}",
|
||||||
|
"deleteContainer": "ลบ",
|
||||||
|
"addContainer": "เพิ่ม Container",
|
||||||
|
"addNetwork": "เพิ่ม เครือข่าย",
|
||||||
|
"disableauth.message1": "คุณแน่ใจหรือไม่ว่าต้องการ <strong>ปิดใช้งานการตรวจสอบสิทธิ์</strong>?",
|
||||||
|
"disableauth.message2": "ได้รับการออกแบบมาสำหรับสถานการณ์ <strong>ที่คุณตั้งใจจะใช้การตรวจสอบสิทธิ์ของบุคคลที่สาม</strong> หน้า Dockge เช่น Cloudflare Access, Authelia หรือกลไกการตรวจสอบสิทธิ์อื่นๆ",
|
||||||
|
"passwordNotMatchMsg": "รหัสผ่านซ้ำไม่ตรงกัน",
|
||||||
|
"autoGet": "รับอัตโนมัติ",
|
||||||
|
"add": "เพิ่ม",
|
||||||
|
"Edit": "แก้ไข",
|
||||||
|
"applyToYAML": "นำไปใช้เป็น YAML",
|
||||||
|
"createExternalNetwork": "สร้าง",
|
||||||
|
"addInternalNetwork": "เพิ่ม",
|
||||||
|
"Save": "บันทึก",
|
||||||
|
"Language": "ภาษา",
|
||||||
|
"Current User": "ผู้ใช้งานปัจจุบัน",
|
||||||
|
"Change Password": "เปลี่ยนรหัสผ่าน",
|
||||||
|
"Current Password": "รหัสผ่านปัจจุบัน",
|
||||||
|
"New Password": "รหัสผ่านใหม่",
|
||||||
|
"Repeat New Password": "รหัสผ่านใหม่ซ้ำ",
|
||||||
|
"Update Password": "อัปเดตรหัสผ่าน",
|
||||||
|
"Advanced": "ขั้นสูง",
|
||||||
|
"Please use this option carefully!": "โปรดใช้ตัวเลือกนี้อย่างระมัดระวัง!",
|
||||||
|
"Enable Auth": "เปิดใช้งาน Auth",
|
||||||
|
"Disable Auth": "ปิดใช้งาน Auth",
|
||||||
|
"I understand, please disable": "ฉันเข้าใจ กรุณาปิดการใช้งาน",
|
||||||
|
"Leave": "ออก",
|
||||||
|
"Frontend Version": "เวอร์ชัน Frontend",
|
||||||
|
"Check Update On GitHub": "ตรวจสอบการอัปเดตบน GitHub",
|
||||||
|
"Show update if available": "แสดงการอัปเดตหากมี",
|
||||||
|
"Also check beta release": "สามารถตรวจสอบรุ่นเบต้าได้",
|
||||||
|
"Remember me": "จดจำฉัน",
|
||||||
|
"Login": "เข้าสู่ระบบ",
|
||||||
|
"Username": "ชื่อผู้ใช้",
|
||||||
|
"Password": "รหัสผ่าน",
|
||||||
|
"Settings": "การตั้งค่า",
|
||||||
|
"Logout": "ออกจากระบบ",
|
||||||
|
"Lowercase only": "ตัวเล็กทั้งหมด",
|
||||||
|
"Convert to Compose": "แปลงเป็น Compose",
|
||||||
|
"Docker Run": "เรียกใช้ Docker",
|
||||||
|
"active": "ใช้งานอยู่",
|
||||||
|
"exited": "ปิดลงแล้ว",
|
||||||
|
"inactive": "ไม่ได้ใช้งาน",
|
||||||
|
"Appearance": "รูปลักษณ์",
|
||||||
|
"Security": "ความปลอดภัย",
|
||||||
|
"About": "เกี่ยวกับ",
|
||||||
|
"Allowed commands:": "คำสั่งที่อนุญาต:",
|
||||||
|
"Internal Networks": "เครือข่ายภายใน",
|
||||||
|
"External Networks": "เครือข่ายภายนอก",
|
||||||
|
"No External Networks": "ไม่มีเครือข่ายภายนอก"
|
||||||
|
}
|
94
frontend/src/lang/tr.json
Normal file
94
frontend/src/lang/tr.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "Türkçe",
|
||||||
|
"Create your admin account": "Yönetici hesabınızı oluşturun",
|
||||||
|
"authIncorrectCreds": "Yanlış kullanıcı adı veya parola.",
|
||||||
|
"PasswordsDoNotMatch": "Parolalar eşleşmiyor.",
|
||||||
|
"Repeat Password": "Parolayı Tekrarla",
|
||||||
|
"Create": "Oluştur",
|
||||||
|
"signedInDisp": "{0} olarak oturum açıldı",
|
||||||
|
"signedInDispDisabled": "Yetkilendirme Devre Dışı.",
|
||||||
|
"home": "Anasayfa",
|
||||||
|
"console": "Konsol",
|
||||||
|
"registry": "Kayıt Defteri",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "İlk yığınınızı oluşturun!",
|
||||||
|
"stackName" : "Yığın Adı",
|
||||||
|
"deployStack": "Dağıtmak",
|
||||||
|
"deleteStack": "Sil",
|
||||||
|
"stopStack": "Dudur",
|
||||||
|
"restartStack": "Yeniden Başlat",
|
||||||
|
"updateStack": "Güncelle",
|
||||||
|
"startStack": "Başlat",
|
||||||
|
"editStack": "Düzenle",
|
||||||
|
"discardStack": "Çıkar",
|
||||||
|
"saveStackDraft": "Kaydet",
|
||||||
|
"notAvailableShort" : "N/A",
|
||||||
|
"deleteStackMsg": "Bu yığını silmek istediğinizden emin misiniz?",
|
||||||
|
"stackNotManagedByDockgeMsg": "Bu yığın Dockge tarafından yönetilmemektedir.",
|
||||||
|
"primaryHostname": "Birincil Ana Bilgisayar Adı",
|
||||||
|
"general": "Genel",
|
||||||
|
"container": "Konteyner | Konteynerler",
|
||||||
|
"scanFolder": "Yığınlar Klasörünü Tara",
|
||||||
|
"dockerImage": "Görüntü",
|
||||||
|
"restartPolicyUnlessStopped": "Durdurulana Kadar",
|
||||||
|
"restartPolicyAlways": "Her zaman",
|
||||||
|
"restartPolicyOnFailure": "Başarısızlıkta",
|
||||||
|
"restartPolicyNo": "Hayır",
|
||||||
|
"environmentVariable": "Ortam Değişkeni | Ortam Değişkenleri",
|
||||||
|
"restartPolicy": "Yeniden Başlatma Politikası",
|
||||||
|
"containerName": "Konteyner Adı",
|
||||||
|
"port": "Port | Portlar",
|
||||||
|
"volume": "Disk Bölümü | Disk Bölümleri",
|
||||||
|
"network": "Ağ | Ağlar",
|
||||||
|
"dependsOn": "Konteyner Bağımlılığı | Konteyner Bağımlılıkları",
|
||||||
|
"addListItem": "{0} Ekle",
|
||||||
|
"deleteContainer": "Sil",
|
||||||
|
"addContainer": "Konteyner Ekle",
|
||||||
|
"addNetwork": "Ağ Ekle",
|
||||||
|
"disableauth.message1": "<strong>Kimlik doğrulamayı devre dışı</strong> bırakmak istediğinizden emin misiniz?",
|
||||||
|
"disableauth.message2": "Cloudflare Access, Authelia veya diğer kimlik doğrulama mekanizmaları gibi Uptime Kuma'nın önünde <strong>üçüncü taraf kimlik doğrulaması uygulamak</strong> istediğiniz senaryolar için tasarlanmıştır.",
|
||||||
|
"passwordNotMatchMsg": "Tekrarlanan parola eşleşmiyor.",
|
||||||
|
"autoGet": "Otomatik Al",
|
||||||
|
"add": "Ekle",
|
||||||
|
"Edit": "Düzenle",
|
||||||
|
"applyToYAML": "YAML'ye uygulayın",
|
||||||
|
"createExternalNetwork": "Oluştur",
|
||||||
|
"addInternalNetwork": "Ekle",
|
||||||
|
"Save": "Kaydet",
|
||||||
|
"Language": "Dil",
|
||||||
|
"Current User": "Mevcut Kullanıcı",
|
||||||
|
"Change Password": "Mevcut Parola",
|
||||||
|
"Current Password": "Mevcut Parola",
|
||||||
|
"New Password": "Yeni Parola",
|
||||||
|
"Repeat New Password": "Yeni Parolayı Tekrarla",
|
||||||
|
"Update Password": "Parolayı Güncelle",
|
||||||
|
"Advanced": "Gelişmiş",
|
||||||
|
"Please use this option carefully!": "Lütfen bu seçeneği dikkatli kullanın!",
|
||||||
|
"Enable Auth": "Kimlik Doğrulamayı Etkinleştir",
|
||||||
|
"Disable Auth": "Kimlik Doğrulamayı Devre Dışı Bırak",
|
||||||
|
"I understand, please disable": "Anlıyorum, lütfen devre dışı bırakın",
|
||||||
|
"Leave": "Ayrıl",
|
||||||
|
"Frontend Version": "Frontend Versiyon",
|
||||||
|
"Check Update On GitHub": "GitHub'da Güncellemeyi Kontrol Edin",
|
||||||
|
"Show update if available": "Varsa güncellemeyi göster",
|
||||||
|
"Also check beta release": "Ayrıca beta sürümünü kontrol edin",
|
||||||
|
"Remember me": "Beni Hatırla",
|
||||||
|
"Login": "Oturum Aç",
|
||||||
|
"Username": "Kullanıcı Adı",
|
||||||
|
"Password": "Parola",
|
||||||
|
"Settings": "Ayarlar",
|
||||||
|
"Logout": "Oturumu Kapat",
|
||||||
|
"Lowercase only": "Yalnızca küçük harf",
|
||||||
|
"Convert to Compose": "Compose'a Dönüştür",
|
||||||
|
"Docker Run": "Docker Run",
|
||||||
|
"active": "aktif",
|
||||||
|
"exited": "çıkış yaptı",
|
||||||
|
"inactive": "aktif değil",
|
||||||
|
"Appearance": "Görünüm",
|
||||||
|
"Security": "Güvenlik",
|
||||||
|
"About": "Hakkında",
|
||||||
|
"Allowed commands:": "İzin verilen komutlar:",
|
||||||
|
"Internal Networks": "İç Ağlar",
|
||||||
|
"External Networks": "Dış Ağlar",
|
||||||
|
"No External Networks": "Dış Ağ Yok"
|
||||||
|
}
|
94
frontend/src/lang/ur.json
Normal file
94
frontend/src/lang/ur.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "اردو",
|
||||||
|
"Create your admin account": "اپنا ایڈمن اکاؤنٹ بنائیں",
|
||||||
|
"authIncorrectCreds": "غلط صارف نام یا پاس ورڈ.",
|
||||||
|
"PasswordsDoNotMatch": "پاس ورڈز کوئی مماثل نہیں ہیں۔",
|
||||||
|
"Repeat Password": "پاس ورڈ دوبارہ لکھیے",
|
||||||
|
"Create": "بنانا",
|
||||||
|
"signedInDisp": "بطور {0} سائن ان",
|
||||||
|
"signedInDispDisabled": "توثیق غیر فعال۔",
|
||||||
|
"home": "گھر",
|
||||||
|
"console": "تسلی",
|
||||||
|
"registry": "رجسٹری",
|
||||||
|
"compose": "تحریر",
|
||||||
|
"addFirstStackMsg": "اپنا پہلا اسٹیک کمپوز کریں!",
|
||||||
|
"stackName" : "اسٹیک کا نام",
|
||||||
|
"deployStack": "تعینات",
|
||||||
|
"deleteStack": "حذف کریں",
|
||||||
|
"stopStack": "روکو",
|
||||||
|
"restartStack": "دوبارہ شروع کریں",
|
||||||
|
"updateStack": "اپ ڈیٹ",
|
||||||
|
"startStack": "شروع کریں۔",
|
||||||
|
"editStack": "ترمیم",
|
||||||
|
"discardStack": "رد کر دیں۔",
|
||||||
|
"saveStackDraft": "محفوظ کریں۔",
|
||||||
|
"notAvailableShort" : "N / A",
|
||||||
|
"deleteStackMsg": "کیا آپ واقعی اس اسٹیک کو حذف کرنا چاہتے ہیں؟",
|
||||||
|
"stackNotManagedByDockgeMsg": "یہ اسٹیک Dockge کے زیر انتظام نہیں ہے۔",
|
||||||
|
"primaryHostname": "بنیادی میزبان نام",
|
||||||
|
"general": "جنرل",
|
||||||
|
"container": "کنٹینر | کنٹینرز",
|
||||||
|
"scanFolder": "اسٹیک فولڈر کو اسکین کریں۔",
|
||||||
|
"dockerImage": "تصویر",
|
||||||
|
"restartPolicyUnlessStopped": "جب تک روکا نہیں جاتا",
|
||||||
|
"restartPolicyAlways": "ہمیشہ",
|
||||||
|
"restartPolicyOnFailure": "ناکامی پر",
|
||||||
|
"restartPolicyNo": "نہیں",
|
||||||
|
"environmentVariable": "ماحولیاتی متغیر | ماحولیاتی تغیرات",
|
||||||
|
"restartPolicy": "پالیسی کو دوبارہ شروع کریں",
|
||||||
|
"containerName": "کنٹینر کا نام",
|
||||||
|
"port": "پورٹ | بندرگاہیں",
|
||||||
|
"volume": "والیوم | جلدیں",
|
||||||
|
"network": "نیٹ ورک | نیٹ ورکس",
|
||||||
|
"dependsOn": "کنٹینر انحصار | کنٹینر انحصار",
|
||||||
|
"addListItem": "شامل کریں {0}",
|
||||||
|
"deleteContainer": "حذف کریں",
|
||||||
|
"addContainer": "کنٹینر شامل کریں",
|
||||||
|
"addNetwork": "نیٹ ورک شامل کریں",
|
||||||
|
"disableauth.message1": "کیا آپ واقعی <strong>تصدیق کو غیر فعال</strong> کرنا چاہتے ہیں؟",
|
||||||
|
"disableauth.message2": "یہ ان منظرناموں کے لیے ڈیزائن کیا گیا ہے جہاں <strong>آپ کا ارادہ ہے تیسرے فریق کی توثیق کو لاگو کرنے کا</strong> Dockge کے سامنے جیسے Cloudflare Access، Authelia یا دیگر تصدیقی طریقہ کار۔",
|
||||||
|
"passwordNotMatchMsg": "دہرانے والا پاس ورڈ مماثل نہیں ہے۔",
|
||||||
|
"autoGet": "آٹو حاصل کریں",
|
||||||
|
"add": "شامل کریں",
|
||||||
|
"Edit": "ترمیم",
|
||||||
|
"applyToYAML": "YAML پر درخواست دیں۔",
|
||||||
|
"createExternalNetwork": "بنانا",
|
||||||
|
"addInternalNetwork": "شامل کریں",
|
||||||
|
"Save": "محفوظ کریں",
|
||||||
|
"Language": "زبان",
|
||||||
|
"Current User": "موجودہ صارف",
|
||||||
|
"Change Password": "پاس ورڈ تبدیل کریں",
|
||||||
|
"Current Password": "موجودہ خفیہ لفظ",
|
||||||
|
"New Password": "نیا پاس ورڈ",
|
||||||
|
"Repeat New Password": "نیا پاس ورڈ دہرائیں",
|
||||||
|
"Update Password": "پاس ورڈ اپ ڈیٹ کریں",
|
||||||
|
"Advanced": "ترقی یافتہ",
|
||||||
|
"Please use this option carefully!": "براہ کرم اس اختیار کو احتیاط سے استعمال کریں!",
|
||||||
|
"Enable Auth": "تصدیق کو فعال کریں۔",
|
||||||
|
"Disable Auth": "توثیق کو غیر فعال کریں۔",
|
||||||
|
"I understand, please disable": "میں سمجھتا ہوں، براہ کرم غیر فعال کریں۔",
|
||||||
|
"Leave": "چھوڑ دو",
|
||||||
|
"Frontend Version": "فرنٹ اینڈ ورژن",
|
||||||
|
"Check Update On GitHub": "گیتوب پر اپ ڈیٹ چیک کریں۔",
|
||||||
|
"Show update if available": "اگر دستیاب ہو تو اپ ڈیٹ دکھائیں",
|
||||||
|
"Also check beta release": "بیٹا ریلیز بھی چیک کریں",
|
||||||
|
"Remember me": "مجھے پہچانتے ہو",
|
||||||
|
"Login": "لاگ ان کریں",
|
||||||
|
"Username": "صارف نام",
|
||||||
|
"Password": "پاس ورڈ",
|
||||||
|
"Settings": "ترتیبات",
|
||||||
|
"Logout": "لاگ آوٹ",
|
||||||
|
"Lowercase only": "صرف لوئر کیس",
|
||||||
|
"Convert to Compose": "تحریر میں تبدیل کریں",
|
||||||
|
"Docker Run": "ڈاکر رن",
|
||||||
|
"active": "فعال",
|
||||||
|
"exited": "باہر نکلا",
|
||||||
|
"inactive": "غیر فعال",
|
||||||
|
"Appearance": "ظہور",
|
||||||
|
"Security": "سیکورٹی",
|
||||||
|
"About": "کے بارے میں",
|
||||||
|
"Allowed commands:": "اجازت شدہ احکامات:",
|
||||||
|
"Internal Networks": "اندرونی نیٹ ورکس",
|
||||||
|
"External Networks": "بیرونی نیٹ ورکس",
|
||||||
|
"No External Networks": "کوئی بیرونی نیٹ ورک نہیں"
|
||||||
|
}
|
94
frontend/src/lang/zh-CN.json
Normal file
94
frontend/src/lang/zh-CN.json
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
{
|
||||||
|
"languageName": "简体中文",
|
||||||
|
"Create your admin account": "创建你的管理员账号",
|
||||||
|
"authIncorrectCreds": "用户名或密码错误",
|
||||||
|
"PasswordsDoNotMatch": "两次输入的密码不一致。",
|
||||||
|
"Repeat Password": "重复以确认密码",
|
||||||
|
"Create": "创建",
|
||||||
|
"signedInDisp": "当前用户: {0}",
|
||||||
|
"signedInDispDisabled": "已禁用身份验证",
|
||||||
|
"home": "主页",
|
||||||
|
"console": "终端",
|
||||||
|
"registry": "镜像仓库",
|
||||||
|
"compose": "Compose",
|
||||||
|
"addFirstStackMsg": "组合你的第一个堆栈!",
|
||||||
|
"stackName" : "堆栈名称",
|
||||||
|
"deployStack": "部署",
|
||||||
|
"deleteStack": "删除",
|
||||||
|
"stopStack": "停止",
|
||||||
|
"restartStack": "重启",
|
||||||
|
"updateStack": "更新",
|
||||||
|
"startStack": "启动",
|
||||||
|
"editStack": "编辑",
|
||||||
|
"discardStack": "放弃",
|
||||||
|
"saveStackDraft": "保存",
|
||||||
|
"notAvailableShort" : "不可用",
|
||||||
|
"deleteStackMsg": "你确定要删除这个堆栈吗?",
|
||||||
|
"stackNotManagedByDockgeMsg": "这个堆栈不由Dockge管理",
|
||||||
|
"primaryHostname": "主机名",
|
||||||
|
"general": "常规",
|
||||||
|
"container": "容器 | 容器组",
|
||||||
|
"scanFolder": "扫描堆栈文件夹",
|
||||||
|
"dockerImage": "镜像",
|
||||||
|
"restartPolicyUnlessStopped": "除非手动停止",
|
||||||
|
"restartPolicyAlways": "始终",
|
||||||
|
"restartPolicyOnFailure": "在失败时",
|
||||||
|
"restartPolicyNo": "不重启",
|
||||||
|
"environmentVariable": "环境变量 | 环境变量组",
|
||||||
|
"restartPolicy": "重启策略",
|
||||||
|
"containerName": "容器名",
|
||||||
|
"port": "端口 | 端口组",
|
||||||
|
"volume": "数据卷 | 数据卷组",
|
||||||
|
"network": "网络 | 网络组",
|
||||||
|
"dependsOn": "容器依赖 | 容器依赖关系",
|
||||||
|
"addListItem": "添加 {0}",
|
||||||
|
"deleteContainer": "删除",
|
||||||
|
"addContainer": "添加容器",
|
||||||
|
"addNetwork": "添加网络",
|
||||||
|
"disableauth.message1": "你确定要<strong>禁用身份验证</strong>吗?",
|
||||||
|
"disableauth.message2": "该选项设计用于某些场景,<strong>例如在Dockge之上接入第三方认证</strong>,比如Cloudflare Access、Authelia或其他认证机制,如果你不清楚这个选项的作用,不要禁用验证!",
|
||||||
|
"passwordNotMatchMsg": "两次输入的密码不一致。",
|
||||||
|
"autoGet": "自动获取",
|
||||||
|
"add": "添加",
|
||||||
|
"Edit": "编辑",
|
||||||
|
"applyToYAML": "应用到YAML",
|
||||||
|
"createExternalNetwork": "创建",
|
||||||
|
"addInternalNetwork": "添加",
|
||||||
|
"Save": "保存",
|
||||||
|
"Language": "语言",
|
||||||
|
"Current User": "当前用户",
|
||||||
|
"Change Password": "更换密码",
|
||||||
|
"Current Password": "当前密码",
|
||||||
|
"New Password": "新密码",
|
||||||
|
"Repeat New Password": "重复以确认新密码",
|
||||||
|
"Update Password": "更新密码",
|
||||||
|
"Advanced": "进阶",
|
||||||
|
"Please use this option carefully!": "请谨慎使用该选项!",
|
||||||
|
"Enable Auth": "启用验证",
|
||||||
|
"Disable Auth": "禁用验证",
|
||||||
|
"I understand, please disable": "我已了解风险,确认禁用",
|
||||||
|
"Leave": "离开",
|
||||||
|
"Frontend Version": "前端版本",
|
||||||
|
"Check Update On GitHub": "在GitHub上检查更新",
|
||||||
|
"Show update if available": "有更新时提醒我",
|
||||||
|
"Also check beta release": "同时检查Beta渠道更新",
|
||||||
|
"Remember me": "记住我",
|
||||||
|
"Login": "登录",
|
||||||
|
"Username": "用户名",
|
||||||
|
"Password": "密码",
|
||||||
|
"Settings": "设置",
|
||||||
|
"Logout": "登出",
|
||||||
|
"Lowercase only": "仅小写字母",
|
||||||
|
"Convert to Compose": "转换为Compose格式",
|
||||||
|
"Docker Run": "Docker启动",
|
||||||
|
"active": "已启动",
|
||||||
|
"exited": "已退出",
|
||||||
|
"inactive": "未启动",
|
||||||
|
"Appearance": "外观",
|
||||||
|
"Security": "安全",
|
||||||
|
"About": "关于",
|
||||||
|
"Allowed commands:": "允许使用的指令:",
|
||||||
|
"Internal Networks": "内部网络",
|
||||||
|
"External Networks": "外部网络",
|
||||||
|
"No External Networks": "无外部网络"
|
||||||
|
}
|
|
@ -40,6 +40,13 @@
|
||||||
<font-awesome-icon icon="stop" class="me-1" />
|
<font-awesome-icon icon="stop" class="me-1" />
|
||||||
{{ $t("stopStack") }}
|
{{ $t("stopStack") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<BDropdown v-if="!isEditMode && active" right text="" variant="normal">
|
||||||
|
<BDropdownItem @click="downStack">
|
||||||
|
<font-awesome-icon icon="stop" class="me-1" />
|
||||||
|
{{ $t("downStack") }}
|
||||||
|
</BDropdownItem>
|
||||||
|
</BDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button v-if="isEditMode && !isAdd" class="btn btn-normal" :disabled="processing" @click="discardStack">{{ $t("discardStack") }}</button>
|
<button v-if="isEditMode && !isAdd" class="btn btn-normal" :disabled="processing" @click="discardStack">{{ $t("discardStack") }}</button>
|
||||||
|
@ -71,7 +78,7 @@
|
||||||
<div>
|
<div>
|
||||||
<label for="name" class="form-label">{{ $t("stackName") }}</label>
|
<label for="name" class="form-label">{{ $t("stackName") }}</label>
|
||||||
<input id="name" v-model="stack.name" type="text" class="form-control" required @blur="stackNameToLowercase">
|
<input id="name" v-model="stack.name" type="text" class="form-control" required @blur="stackNameToLowercase">
|
||||||
<div class="form-text">Lowercase only</div>
|
<div class="form-text">{{ $t("Lowercase only") }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -118,7 +125,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<h4 class="mb-3">compose.yaml</h4>
|
<h4 class="mb-3">{{ stack.composeFileName }}</h4>
|
||||||
|
|
||||||
<!-- YAML editor -->
|
<!-- YAML editor -->
|
||||||
<div class="shadow-box mb-3 editor-box" :class="{'edit-mode' : isEditMode}">
|
<div class="shadow-box mb-3 editor-box" :class="{'edit-mode' : isEditMode}">
|
||||||
|
@ -473,6 +480,15 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
downStack() {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
this.$root.getSocket().emit("downStack", this.stack.name, (res) => {
|
||||||
|
this.processing = false;
|
||||||
|
this.$root.toastRes(res);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
restartStack() {
|
restartStack() {
|
||||||
this.processing = true;
|
this.processing = true;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
Allowed commands:
|
{{ $t("Allowed commands:") }}
|
||||||
<template v-for="(command, index) in allowedCommandList" :key="command">
|
<template v-for="(command, index) in allowedCommandList" :key="command">
|
||||||
<code>{{ command }}</code>
|
<code>{{ command }}</code>
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="mb-3">Docker Run</h2>
|
<h2 class="mb-3">{{ $t("Docker Run") }}</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<textarea id="name" v-model="dockerRunCommand" type="text" class="form-control docker-run" required placeholder="docker run ..."></textarea>
|
<textarea id="name" v-model="dockerRunCommand" type="text" class="form-control docker-run" required placeholder="docker run ..."></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn-normal btn" @click="convertDockerRun">Convert to Compose</button>
|
<button class="btn-normal btn" @click="convertDockerRun">{{ $t("Convert to Compose") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
<router-view ref="child" />
|
<router-view ref="child" />
|
||||||
|
|
|
@ -75,7 +75,7 @@ export default {
|
||||||
subMenus() {
|
subMenus() {
|
||||||
return {
|
return {
|
||||||
general: {
|
general: {
|
||||||
title: this.$t("General"),
|
title: this.$t("general"),
|
||||||
},
|
},
|
||||||
appearance: {
|
appearance: {
|
||||||
title: this.$t("Appearance"),
|
title: this.$t("Appearance"),
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { POSITION } from "vue-toastification";
|
||||||
*
|
*
|
||||||
* Generated by Trelent
|
* Generated by Trelent
|
||||||
*/
|
*/
|
||||||
function getTimezoneOffset(timeZone) {
|
function getTimezoneOffset(timeZone : string) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const tzString = now.toLocaleString("en-US", {
|
const tzString = now.toLocaleString("en-US", {
|
||||||
timeZone,
|
timeZone,
|
||||||
|
@ -124,33 +124,6 @@ export function hostNameRegexPattern(mqtt = false) {
|
||||||
return `${ipRegexPattern}|${hostNameRegexPattern}`;
|
return `${ipRegexPattern}|${hostNameRegexPattern}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tag color options
|
|
||||||
* Shared between components
|
|
||||||
* @param {any} self Component
|
|
||||||
* @returns {object[]} Colour options
|
|
||||||
*/
|
|
||||||
export function colorOptions(self) {
|
|
||||||
return [
|
|
||||||
{ name: self.$t("Gray"),
|
|
||||||
color: "#4B5563" },
|
|
||||||
{ name: self.$t("Red"),
|
|
||||||
color: "#DC2626" },
|
|
||||||
{ name: self.$t("Orange"),
|
|
||||||
color: "#D97706" },
|
|
||||||
{ name: self.$t("Green"),
|
|
||||||
color: "#059669" },
|
|
||||||
{ name: self.$t("Blue"),
|
|
||||||
color: "#2563EB" },
|
|
||||||
{ name: self.$t("Indigo"),
|
|
||||||
color: "#4F46E5" },
|
|
||||||
{ name: self.$t("Purple"),
|
|
||||||
color: "#7C3AED" },
|
|
||||||
{ name: self.$t("Pink"),
|
|
||||||
color: "#DB2777" },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the toast timeout settings from storage.
|
* Loads the toast timeout settings from storage.
|
||||||
* @returns {object} The toast plugin options object.
|
* @returns {object} The toast plugin options object.
|
||||||
|
|
1
frontend/src/vite-env.d.ts
vendored
1
frontend/src/vite-env.d.ts
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable */
|
||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
declare module "*.vue" {
|
declare module "*.vue" {
|
||||||
|
|
22
package.json
22
package.json
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "dockge",
|
"name": "dockge",
|
||||||
"version": "1.0.4",
|
"version": "1.1.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fmt": "eslint \"**/*.{ts,vue}\" --fix",
|
"fmt": "eslint \"**/*.{ts,vue}\" --fix",
|
||||||
"lint": "eslint \"**/*.{ts,vue}\"",
|
"lint": "eslint \"**/*.{ts,vue}\"",
|
||||||
|
"check-ts": "tsc --noEmit",
|
||||||
"start": "tsx ./backend/index.ts",
|
"start": "tsx ./backend/index.ts",
|
||||||
"dev:backend": "cross-env NODE_ENV=development tsx watch ./backend/index.ts",
|
"dev:backend": "cross-env NODE_ENV=development tsx watch --inspect ./backend/index.ts",
|
||||||
"dev:frontend": "cross-env NODE_ENV=development vite --host --config ./frontend/vite.config.ts",
|
"dev:frontend": "cross-env NODE_ENV=development vite --host --config ./frontend/vite.config.ts",
|
||||||
"release-final": "tsx ./extra/test-docker.ts && tsx extra/update-version.ts && pnpm run build:frontend && npm run build:docker",
|
"release-final": "tsx ./extra/test-docker.ts && tsx extra/update-version.ts && pnpm run build:frontend && npm run build:docker",
|
||||||
"build:frontend": "vite build --config ./frontend/vite.config.ts",
|
"build:frontend": "vite build --config ./frontend/vite.config.ts",
|
||||||
|
@ -14,11 +15,11 @@
|
||||||
"build:docker": "node ./extra/env2arg.js docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:latest -t louislam/dockge:1 -t louislam/dockge:$VERSION --target release -f ./docker/Dockerfile . --push",
|
"build:docker": "node ./extra/env2arg.js docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:latest -t louislam/dockge:1 -t louislam/dockge:$VERSION --target release -f ./docker/Dockerfile . --push",
|
||||||
"build:docker-nightly": "pnpm run build:frontend && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:nightly --target nightly -f ./docker/Dockerfile . --push",
|
"build:docker-nightly": "pnpm run build:frontend && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:nightly --target nightly -f ./docker/Dockerfile . --push",
|
||||||
"start-docker": "docker run --rm -p 5001:5001 --name dockge louislam/dockge:latest",
|
"start-docker": "docker run --rm -p 5001:5001 --name dockge louislam/dockge:latest",
|
||||||
"mark-as-nightly": "tsx ./extra/mark-as-nightly.ts"
|
"mark-as-nightly": "tsx ./extra/mark-as-nightly.ts",
|
||||||
|
"reformat-changelog": "tsx ./extra/reformat-changelog.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/jetbrains-mono": "^5.0.17",
|
"@homebridge/node-pty-prebuilt-multiarch": "~0.11.11",
|
||||||
"@homebridge/node-pty-prebuilt-multiarch": "~0.11.10",
|
|
||||||
"@louislam/sqlite3": "~15.1.6",
|
"@louislam/sqlite3": "~15.1.6",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"check-password-strength": "~2.0.7",
|
"check-password-strength": "~2.0.7",
|
||||||
|
@ -34,8 +35,8 @@
|
||||||
"jwt-decode": "~3.1.2",
|
"jwt-decode": "~3.1.2",
|
||||||
"knex": "~2.5.1",
|
"knex": "~2.5.1",
|
||||||
"limiter-es6-compat": "~2.1.2",
|
"limiter-es6-compat": "~2.1.2",
|
||||||
"mysql2": "^3.6.3",
|
"mysql2": "~3.6.3",
|
||||||
"redbean-node": "0.3.2",
|
"redbean-node": "~0.3.3",
|
||||||
"socket.io": "~4.7.2",
|
"socket.io": "~4.7.2",
|
||||||
"socket.io-client": "~4.7.2",
|
"socket.io-client": "~4.7.2",
|
||||||
"timezones-list": "~3.0.2",
|
"timezones-list": "~3.0.2",
|
||||||
|
@ -45,17 +46,20 @@
|
||||||
"yaml": "~2.3.4"
|
"yaml": "~2.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@actions/github": "^6.0.0",
|
||||||
|
"@fontsource/jetbrains-mono": "^5.0.17",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
||||||
"@fortawesome/free-regular-svg-icons": "6.4.2",
|
"@fortawesome/free-regular-svg-icons": "6.4.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "6.4.2",
|
"@fortawesome/free-solid-svg-icons": "6.4.2",
|
||||||
"@fortawesome/vue-fontawesome": "3.0.3",
|
"@fortawesome/vue-fontawesome": "3.0.3",
|
||||||
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/bootstrap": "~5.2.9",
|
"@types/bootstrap": "~5.2.9",
|
||||||
"@types/command-exists": "~1.2.3",
|
"@types/command-exists": "~1.2.3",
|
||||||
"@types/express": "~4.17.21",
|
"@types/express": "~4.17.21",
|
||||||
"@types/jsonwebtoken": "~9.0.5",
|
"@types/jsonwebtoken": "~9.0.5",
|
||||||
"@typescript-eslint/eslint-plugin": "~6.8.0",
|
"@typescript-eslint/eslint-plugin": "~6.8.0",
|
||||||
"@typescript-eslint/parser": "~6.8.0",
|
"@typescript-eslint/parser": "~6.8.0",
|
||||||
"@vitejs/plugin-vue": "~4.3.4",
|
"@vitejs/plugin-vue": "~4.5.0",
|
||||||
"bootstrap": "5.3.2",
|
"bootstrap": "5.3.2",
|
||||||
"bootstrap-vue-next": "~0.14.10",
|
"bootstrap-vue-next": "~0.14.10",
|
||||||
"cross-env": "~7.0.3",
|
"cross-env": "~7.0.3",
|
||||||
|
@ -66,7 +70,7 @@
|
||||||
"sass": "~1.68.0",
|
"sass": "~1.68.0",
|
||||||
"typescript": "~5.2.2",
|
"typescript": "~5.2.2",
|
||||||
"unplugin-vue-components": "~0.25.2",
|
"unplugin-vue-components": "~0.25.2",
|
||||||
"vite": "~4.5.0",
|
"vite": "~5.0.0",
|
||||||
"vite-plugin-compression": "~0.5.1",
|
"vite-plugin-compression": "~0.5.1",
|
||||||
"vue": "~3.3.8",
|
"vue": "~3.3.8",
|
||||||
"vue-eslint-parser": "~9.3.2",
|
"vue-eslint-parser": "~9.3.2",
|
||||||
|
|
653
pnpm-lock.yaml
653
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,10 @@
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"moduleResolution": "bundler"
|
"moduleResolution": "bundler",
|
||||||
}
|
"skipLibCheck": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"backend/**/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue