From 1f9dea648f3a34e2769a76a9c87291789b192625 Mon Sep 17 00:00:00 2001 From: Burak Ozter Date: Tue, 29 Oct 2024 10:14:23 -0300 Subject: [PATCH] add cockpit-docker files. --- ui/cockpit-docker/.cockpit-ci/container | 1 + ui/cockpit-docker/.cockpit-ci/run | 1 + ui/cockpit-docker/.eslintignore | 2 + ui/cockpit-docker/.eslintrc.json | 55 + ui/cockpit-docker/.fmf/version | 1 + .../.github/ISSUE_TEMPLATE/bug_report.md | 31 + ui/cockpit-docker/.github/dependabot.yml | 38 + .../.github/workflows/dependabot.yml | 82 + .../.github/workflows/nightly.yml | 22 + .../.github/workflows/release.yml | 35 + .../workflows/tasks-container-update.yml | 37 + ui/cockpit-docker/.gitignore | 37 + ui/cockpit-docker/.gitmodules | 7 + ui/cockpit-docker/.stylelintrc.json | 39 + ui/cockpit-docker/HACKING.md | 107 + ui/cockpit-docker/LICENSE | 502 +++ ui/cockpit-docker/Makefile | 217 ++ ui/cockpit-docker/README.md | 86 + ui/cockpit-docker/build.js | 108 + .../me.chabad360.docker.metainfo.xml | 16 + ui/cockpit-docker/node-modules-fix.sh | 9 + ui/cockpit-docker/package.json | 61 + ui/cockpit-docker/packaging/debian/control | 22 + ui/cockpit-docker/packaging/debian/copyright | 38 + ui/cockpit-docker/packaging/debian/rules | 13 + .../packaging/debian/source/format | 1 + .../packaging/debian/source/lintian-overrides | 2 + .../packaging/debian/upstream/metadata | 4 + ui/cockpit-docker/packaging/debian/watch | 5 + ui/cockpit-docker/packit.yaml | 80 + ui/cockpit-docker/plans/all.fmf | 23 + ui/cockpit-docker/po/cs.po | 1510 +++++++++ ui/cockpit-docker/po/de.po | 1505 +++++++++ ui/cockpit-docker/po/es.po | 1489 +++++++++ ui/cockpit-docker/po/fi.po | 1484 +++++++++ ui/cockpit-docker/po/fr.po | 1529 ++++++++++ ui/cockpit-docker/po/ja.po | 1467 +++++++++ ui/cockpit-docker/po/ka.po | 1408 +++++++++ ui/cockpit-docker/po/ko.po | 1461 +++++++++ ui/cockpit-docker/po/pl.po | 1508 +++++++++ ui/cockpit-docker/po/sk.po | 1553 ++++++++++ ui/cockpit-docker/po/sv.po | 1484 +++++++++ ui/cockpit-docker/po/tr.po | 1501 +++++++++ ui/cockpit-docker/po/uk.po | 1522 +++++++++ ui/cockpit-docker/po/zh_CN.po | 1479 +++++++++ ui/cockpit-docker/pyproject.toml | 51 + .../src/ContainerCheckpointModal.jsx | 68 + .../src/ContainerCommitModal.jsx | 158 + .../src/ContainerDeleteModal.jsx | 42 + ui/cockpit-docker/src/ContainerDetails.jsx | 80 + ui/cockpit-docker/src/ContainerHeader.jsx | 22 + ui/cockpit-docker/src/ContainerHealthLogs.jsx | 158 + .../src/ContainerIntegration.jsx | 125 + ui/cockpit-docker/src/ContainerLogs.jsx | 174 ++ .../src/ContainerRenameModal.jsx | 107 + .../src/ContainerRestoreModal.jsx | 74 + ui/cockpit-docker/src/ContainerTerminal.css | 7 + ui/cockpit-docker/src/ContainerTerminal.jsx | 265 ++ ui/cockpit-docker/src/Containers.jsx | 611 ++++ ui/cockpit-docker/src/Containers.scss | 93 + ui/cockpit-docker/src/Env.jsx | 96 + ui/cockpit-docker/src/ForceRemoveModal.jsx | 33 + ui/cockpit-docker/src/ImageDeleteModal.jsx | 121 + ui/cockpit-docker/src/ImageDetails.jsx | 47 + ui/cockpit-docker/src/ImageHistory.jsx | 64 + ui/cockpit-docker/src/ImageRunModal.jsx | 1114 +++++++ ui/cockpit-docker/src/ImageRunModal.scss | 47 + ui/cockpit-docker/src/ImageSearchModal.css | 59 + ui/cockpit-docker/src/ImageSearchModal.jsx | 212 ++ ui/cockpit-docker/src/ImageUsedBy.jsx | 44 + ui/cockpit-docker/src/Images.css | 23 + ui/cockpit-docker/src/Images.jsx | 398 +++ ui/cockpit-docker/src/Notification.jsx | 45 + .../src/PruneUnusedContainersModal.jsx | 96 + .../src/PruneUnusedImagesModal.jsx | 101 + ui/cockpit-docker/src/PublishPort.jsx | 142 + ui/cockpit-docker/src/Volume.jsx | 90 + ui/cockpit-docker/src/app.jsx | 617 ++++ ui/cockpit-docker/src/client.js | 172 ++ ui/cockpit-docker/src/docker.scss | 149 + ui/cockpit-docker/src/index.html | 36 + ui/cockpit-docker/src/index.js | 30 + ui/cockpit-docker/src/manifest.json | 16 + ui/cockpit-docker/src/rest.js | 100 + ui/cockpit-docker/src/util.js | 214 ++ ui/cockpit-docker/test/browser/browser.sh | 82 + ui/cockpit-docker/test/browser/main.fmf | 20 + ui/cockpit-docker/test/browser/run-test.sh | 54 + ui/cockpit-docker/test/check-application | 2714 +++++++++++++++++ ui/cockpit-docker/test/reference-image | 1 + ui/cockpit-docker/test/run | 17 + ui/cockpit-docker/test/vm.install | 39 + 92 files changed, 31610 insertions(+) create mode 100644 ui/cockpit-docker/.cockpit-ci/container create mode 120000 ui/cockpit-docker/.cockpit-ci/run create mode 100644 ui/cockpit-docker/.eslintignore create mode 100644 ui/cockpit-docker/.eslintrc.json create mode 100644 ui/cockpit-docker/.fmf/version create mode 100644 ui/cockpit-docker/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 ui/cockpit-docker/.github/dependabot.yml create mode 100644 ui/cockpit-docker/.github/workflows/dependabot.yml create mode 100644 ui/cockpit-docker/.github/workflows/nightly.yml create mode 100644 ui/cockpit-docker/.github/workflows/release.yml create mode 100644 ui/cockpit-docker/.github/workflows/tasks-container-update.yml create mode 100644 ui/cockpit-docker/.gitignore create mode 100644 ui/cockpit-docker/.gitmodules create mode 100644 ui/cockpit-docker/.stylelintrc.json create mode 100644 ui/cockpit-docker/HACKING.md create mode 100644 ui/cockpit-docker/LICENSE create mode 100644 ui/cockpit-docker/Makefile create mode 100644 ui/cockpit-docker/README.md create mode 100755 ui/cockpit-docker/build.js create mode 100644 ui/cockpit-docker/me.chabad360.docker.metainfo.xml create mode 100755 ui/cockpit-docker/node-modules-fix.sh create mode 100644 ui/cockpit-docker/package.json create mode 100644 ui/cockpit-docker/packaging/debian/control create mode 100644 ui/cockpit-docker/packaging/debian/copyright create mode 100755 ui/cockpit-docker/packaging/debian/rules create mode 100644 ui/cockpit-docker/packaging/debian/source/format create mode 100644 ui/cockpit-docker/packaging/debian/source/lintian-overrides create mode 100644 ui/cockpit-docker/packaging/debian/upstream/metadata create mode 100644 ui/cockpit-docker/packaging/debian/watch create mode 100644 ui/cockpit-docker/packit.yaml create mode 100644 ui/cockpit-docker/plans/all.fmf create mode 100644 ui/cockpit-docker/po/cs.po create mode 100644 ui/cockpit-docker/po/de.po create mode 100644 ui/cockpit-docker/po/es.po create mode 100644 ui/cockpit-docker/po/fi.po create mode 100644 ui/cockpit-docker/po/fr.po create mode 100644 ui/cockpit-docker/po/ja.po create mode 100644 ui/cockpit-docker/po/ka.po create mode 100644 ui/cockpit-docker/po/ko.po create mode 100644 ui/cockpit-docker/po/pl.po create mode 100644 ui/cockpit-docker/po/sk.po create mode 100644 ui/cockpit-docker/po/sv.po create mode 100644 ui/cockpit-docker/po/tr.po create mode 100644 ui/cockpit-docker/po/uk.po create mode 100644 ui/cockpit-docker/po/zh_CN.po create mode 100644 ui/cockpit-docker/pyproject.toml create mode 100644 ui/cockpit-docker/src/ContainerCheckpointModal.jsx create mode 100644 ui/cockpit-docker/src/ContainerCommitModal.jsx create mode 100644 ui/cockpit-docker/src/ContainerDeleteModal.jsx create mode 100644 ui/cockpit-docker/src/ContainerDetails.jsx create mode 100644 ui/cockpit-docker/src/ContainerHeader.jsx create mode 100644 ui/cockpit-docker/src/ContainerHealthLogs.jsx create mode 100644 ui/cockpit-docker/src/ContainerIntegration.jsx create mode 100644 ui/cockpit-docker/src/ContainerLogs.jsx create mode 100644 ui/cockpit-docker/src/ContainerRenameModal.jsx create mode 100644 ui/cockpit-docker/src/ContainerRestoreModal.jsx create mode 100644 ui/cockpit-docker/src/ContainerTerminal.css create mode 100644 ui/cockpit-docker/src/ContainerTerminal.jsx create mode 100644 ui/cockpit-docker/src/Containers.jsx create mode 100644 ui/cockpit-docker/src/Containers.scss create mode 100644 ui/cockpit-docker/src/Env.jsx create mode 100644 ui/cockpit-docker/src/ForceRemoveModal.jsx create mode 100644 ui/cockpit-docker/src/ImageDeleteModal.jsx create mode 100644 ui/cockpit-docker/src/ImageDetails.jsx create mode 100644 ui/cockpit-docker/src/ImageHistory.jsx create mode 100644 ui/cockpit-docker/src/ImageRunModal.jsx create mode 100644 ui/cockpit-docker/src/ImageRunModal.scss create mode 100644 ui/cockpit-docker/src/ImageSearchModal.css create mode 100644 ui/cockpit-docker/src/ImageSearchModal.jsx create mode 100644 ui/cockpit-docker/src/ImageUsedBy.jsx create mode 100644 ui/cockpit-docker/src/Images.css create mode 100644 ui/cockpit-docker/src/Images.jsx create mode 100644 ui/cockpit-docker/src/Notification.jsx create mode 100644 ui/cockpit-docker/src/PruneUnusedContainersModal.jsx create mode 100644 ui/cockpit-docker/src/PruneUnusedImagesModal.jsx create mode 100644 ui/cockpit-docker/src/PublishPort.jsx create mode 100644 ui/cockpit-docker/src/Volume.jsx create mode 100644 ui/cockpit-docker/src/app.jsx create mode 100644 ui/cockpit-docker/src/client.js create mode 100644 ui/cockpit-docker/src/docker.scss create mode 100644 ui/cockpit-docker/src/index.html create mode 100644 ui/cockpit-docker/src/index.js create mode 100644 ui/cockpit-docker/src/manifest.json create mode 100644 ui/cockpit-docker/src/rest.js create mode 100644 ui/cockpit-docker/src/util.js create mode 100755 ui/cockpit-docker/test/browser/browser.sh create mode 100644 ui/cockpit-docker/test/browser/main.fmf create mode 100644 ui/cockpit-docker/test/browser/run-test.sh create mode 100755 ui/cockpit-docker/test/check-application create mode 100644 ui/cockpit-docker/test/reference-image create mode 100755 ui/cockpit-docker/test/run create mode 100755 ui/cockpit-docker/test/vm.install diff --git a/ui/cockpit-docker/.cockpit-ci/container b/ui/cockpit-docker/.cockpit-ci/container new file mode 100644 index 0000000..218f87f --- /dev/null +++ b/ui/cockpit-docker/.cockpit-ci/container @@ -0,0 +1 @@ +ghcr.io/cockpit-project/tasks:2024-04-08 diff --git a/ui/cockpit-docker/.cockpit-ci/run b/ui/cockpit-docker/.cockpit-ci/run new file mode 120000 index 0000000..40892d3 --- /dev/null +++ b/ui/cockpit-docker/.cockpit-ci/run @@ -0,0 +1 @@ +cockpit-docker/../test/run \ No newline at end of file diff --git a/ui/cockpit-docker/.eslintignore b/ui/cockpit-docker/.eslintignore new file mode 100644 index 0000000..85f5a45 --- /dev/null +++ b/ui/cockpit-docker/.eslintignore @@ -0,0 +1,2 @@ +node_modules/* +pkg/lib/* diff --git a/ui/cockpit-docker/.eslintrc.json b/ui/cockpit-docker/.eslintrc.json new file mode 100644 index 0000000..dd1624f --- /dev/null +++ b/ui/cockpit-docker/.eslintrc.json @@ -0,0 +1,55 @@ +{ + "root": true, + "env": { + "browser": true, + "es2022": true + }, + "extends": ["eslint:recommended", "standard", "standard-jsx", "standard-react", "plugin:jsx-a11y/recommended"], + "parserOptions": { + "ecmaVersion": 2022 + }, + "plugins": ["react", "react-hooks", "jsx-a11y"], + "rules": { + "indent": ["error", 4, + { + "ObjectExpression": "first", + "CallExpression": {"arguments": "first"}, + "MemberExpression": 2, + "ignoredNodes": [ "JSXAttribute" ] + }], + "newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }], + "no-var": "error", + "lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }], + "prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }], + "react/jsx-indent": ["error", 4], + "semi": ["error", "always", { "omitLastInOneLineBlock": true }], + + "camelcase": "off", + "comma-dangle": "off", + "curly": "off", + "jsx-quotes": "off", + "no-console": "off", + "no-undef": "error", + "quotes": "off", + "react/jsx-curly-spacing": "off", + "react/jsx-indent-props": "off", + "react/jsx-closing-bracket-location": "off", + "react/jsx-closing-tag-location": "off", + "react/jsx-first-prop-new-line": "off", + "react/jsx-curly-newline": "off", + "react/jsx-handler-names": "off", + "react/prop-types": "off", + "react/jsx-no-useless-fragment": "error", + "space-before-function-paren": "off", + "standard/no-callback-literal": "off", + + "jsx-a11y/anchor-is-valid": "off", + + "eqeqeq": "off", + "react/jsx-no-bind": "off" + }, + "globals": { + "require": false, + "module": false + } +} diff --git a/ui/cockpit-docker/.fmf/version b/ui/cockpit-docker/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/ui/cockpit-docker/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/ui/cockpit-docker/.github/ISSUE_TEMPLATE/bug_report.md b/ui/cockpit-docker/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..a649814 --- /dev/null +++ b/ui/cockpit-docker/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: For bugs and general problems +title: +labels: 'bug' +assignees: '' + +--- + +Cockpit version: xxx +Cockpit-docker version: xxx +Docker version: xxx +OS: + + + + + +Steps to reproduce + +1. +2. +3. + + diff --git a/ui/cockpit-docker/.github/dependabot.yml b/ui/cockpit-docker/.github/dependabot.yml new file mode 100644 index 0000000..a6ca0d0 --- /dev/null +++ b/ui/cockpit-docker/.github/dependabot.yml @@ -0,0 +1,38 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + # run these when most of our developers don't work, don't DoS our CI over the day + time: "22:00" + timezone: "Europe/Berlin" + open-pull-requests-limit: 3 + commit-message: + prefix: "[no-test]" + labels: + - "node_modules" + groups: + eslint: + patterns: + - "eslint*" + esbuild: + patterns: + - "esbuild*" + stylelint: + patterns: + - "stylelint*" + xterm: + patterns: + - "xterm*" + patternfly: + patterns: + - "@patternfly*" + + - package-ecosystem: "github-actions" + directory: "/" + open-pull-requests-limit: 3 + labels: + - "no-test" + schedule: + interval: "weekly" diff --git a/ui/cockpit-docker/.github/workflows/dependabot.yml b/ui/cockpit-docker/.github/workflows/dependabot.yml new file mode 100644 index 0000000..0ab8975 --- /dev/null +++ b/ui/cockpit-docker/.github/workflows/dependabot.yml @@ -0,0 +1,82 @@ +name: update node_modules +on: + pull_request_target: + types: [opened, reopened, synchronize, labeled] + +jobs: + dependabot: + environment: npm-update + permissions: + contents: read + pull-requests: write + timeout-minutes: 5 + # 22.04's podman has issues with piping and causes tar errors + runs-on: ubuntu-20.04 + if: ${{ contains(github.event.pull_request.labels.*.name, 'node_modules') }} + + steps: + - name: Clone repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 0 + + - name: Clear node_modules label + uses: actions/github-script@v7 + with: + script: | + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'node_modules' + }); + } catch (e) { + if (e.name == 'HttpError' && e.status == 404) { + /* expected: 404 if label is unset */ + } else { + throw e; + } + } + + - name: Update node_modules for package.json changes + run: | + make tools/node-modules + git config --global user.name "GitHub Workflow" + git config --global user.email "cockpituous@cockpit-project.org" + eval $(ssh-agent) + ssh-add - <<< '${{ secrets.NODE_CACHE_DEPLOY_KEY }}' + ./tools/node-modules install + ./tools/node-modules push + git add node_modules + ssh-add -D + ssh-agent -k + + - name: Clear [no-test] prefix from PR title + if: ${{ contains(github.event.pull_request.title, '[no-test]') }} + uses: actions/github-script@v7 + env: + TITLE: '${{ github.event.pull_request.title }}' + with: + script: | + const title = process.env['TITLE'].replace(/\[no-test\]\W+ /, '') + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + title, + }); + + - name: Force push node_modules update + run: | + # Dependabot prefixes the commit with [no-test] which we don't want to keep in the commit + title=$(git show --pretty="%s" -s | sed -E "s/\[no-test\]\W+ //") + body=$(git show -s --pretty="%b") + git commit --amend -m "${title}" -m "${body}" --no-edit node_modules + eval $(ssh-agent) + ssh-add - <<< '${{ secrets.SELF_DEPLOY_KEY }}' + git push --force 'git@github.com:${{ github.repository }}' '${{ github.head_ref }}' + ssh-add -D + ssh-agent -k diff --git a/ui/cockpit-docker/.github/workflows/nightly.yml b/ui/cockpit-docker/.github/workflows/nightly.yml new file mode 100644 index 0000000..ec7a633 --- /dev/null +++ b/ui/cockpit-docker/.github/workflows/nightly.yml @@ -0,0 +1,22 @@ +name: nightly +on: + schedule: + - cron: '0 1 * * *' + # can be run manually on https://github.com/cockpit-project/cockpit-podman/actions + workflow_dispatch: +jobs: + trigger: + permissions: + statuses: write + runs-on: ubuntu-22.04 + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - name: Trigger updates-testing scenario + run: | + make bots + mkdir -p ~/.config/cockpit-dev + echo "${{ github.token }}" >> ~/.config/cockpit-dev/github-token + TEST_OS=$(PYTHONPATH=bots python3 -c 'from lib.constants import TEST_OS_DEFAULT; print(TEST_OS_DEFAULT)') + bots/tests-trigger --force "-" "${TEST_OS}/updates-testing" "${TEST_OS}/docker-next" diff --git a/ui/cockpit-docker/.github/workflows/release.yml b/ui/cockpit-docker/.github/workflows/release.yml new file mode 100644 index 0000000..0ddfe21 --- /dev/null +++ b/ui/cockpit-docker/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: release +on: + push: + tags: + # this is a glob, not a regexp + - '[0-9]*' +jobs: + source: + runs-on: ubuntu-latest + container: + image: ghcr.io/cockpit-project/tasks:latest + options: --user root + permissions: + # create GitHub release + contents: write + steps: + - name: Clone repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # https://github.blog/2022-04-12-git-security-vulnerability-announced/ + - name: Pacify git's permission check + run: git config --global --add safe.directory /__w/cockpit-docker/cockpit-docker + + - name: Workaround for https://github.com/actions/checkout/pull/697 + run: git fetch --force origin $(git describe --tags):refs/tags/$(git describe --tags) + + - name: Build release + run: make dist + + - name: Publish GitHub release + uses: cockpit-project/action-release@7d2e2657382e8d34f88a24b5987f2b81ea165785 + with: + filename: "cockpit-docker-${{ github.ref_name }}.tar.xz" diff --git a/ui/cockpit-docker/.github/workflows/tasks-container-update.yml b/ui/cockpit-docker/.github/workflows/tasks-container-update.yml new file mode 100644 index 0000000..8473ac6 --- /dev/null +++ b/ui/cockpit-docker/.github/workflows/tasks-container-update.yml @@ -0,0 +1,37 @@ +name: tasks-container-update +on: + schedule: + - cron: '0 2 * * 1' + # can be run manually on https://github.com/cockpit-project/cockpit-podman/actions + workflow_dispatch: +jobs: + tasks-container-update: + environment: self + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + statuses: write + container: + image: ghcr.io/cockpit-project/tasks + options: --user root + steps: + - name: Set up configuration and secrets + run: | + printf '[user]\n\tname = Cockpit Project\n\temail=cockpituous@gmail.com\n' > ~/.gitconfig + mkdir -p ~/.config + echo '${{ secrets.GITHUB_TOKEN }}' > ~/.config/github-token + + - name: Clone repository + uses: actions/checkout@v4 + with: + ssh-key: ${{ secrets.DEPLOY_KEY }} + + # https://github.blog/2022-04-12-git-security-vulnerability-announced/ + - name: Pacify git's permission check + run: git config --global --add safe.directory /__w/cockpit-docker/cockpit-docker + + - name: Run tasks-container-update + run: | + make bots + bots/tasks-container-update diff --git a/ui/cockpit-docker/.gitignore b/ui/cockpit-docker/.gitignore new file mode 100644 index 0000000..841ffcc --- /dev/null +++ b/ui/cockpit-docker/.gitignore @@ -0,0 +1,37 @@ +# Please keep this file sorted (LC_COLLATE=C.UTF-8), +# grouped into the 3 categories below: +# - general patterns (match in all directories) +# - patterns to match files at the toplevel +# - patterns to match files in subdirs + +# general patterns +*.pyc +*.rpm + +# toplevel (/...) +/Test*.html +/Test*.json +/Test*.log +/Test*.log.gz +/Test*.png +/*.whl +/bots +/cockpit-*.tar.xz +/cockpit-docker.spec +/dist/ +/package-lock.json +/pkg/ +/tmp/ +/tools/ +/node_modules/ +/.idea/ +/.vscode/ + +# subdirs (/subdir/...) +/packaging/arch/PKGBUILD +/packaging/debian/changelog +/po/*.pot +/po/LINGUAS +/test/common/ +/test/images/ +/test/static-code diff --git a/ui/cockpit-docker/.gitmodules b/ui/cockpit-docker/.gitmodules new file mode 100644 index 0000000..2ca4fcf --- /dev/null +++ b/ui/cockpit-docker/.gitmodules @@ -0,0 +1,7 @@ +[submodule "test/reference"] + path = test/reference + url = https://github.com/cockpit-project/pixel-test-reference + branch = empty +[submodule "node_modules"] + path = node_modules + url = https://github.com/cockpit-project/node-cache.git diff --git a/ui/cockpit-docker/.stylelintrc.json b/ui/cockpit-docker/.stylelintrc.json new file mode 100644 index 0000000..67a29f0 --- /dev/null +++ b/ui/cockpit-docker/.stylelintrc.json @@ -0,0 +1,39 @@ +{ + "extends": "stylelint-config-standard-scss", + "plugins": [ + "stylelint-use-logical-spec" + ], + "rules": { + "at-rule-empty-line-before": null, + "declaration-empty-line-before": null, + "custom-property-empty-line-before": null, + "comment-empty-line-before": null, + "scss/double-slash-comment-empty-line-before": null, + "scss/dollar-variable-colon-space-after": null, + + "custom-property-pattern": null, + "declaration-block-no-duplicate-properties": null, + "declaration-block-no-redundant-longhand-properties": null, + "declaration-block-no-shorthand-property-overrides": null, + "declaration-block-single-line-max-declarations": null, + "font-family-no-duplicate-names": null, + "function-url-quotes": null, + "keyframes-name-pattern": null, + "media-feature-range-notation": "prefix", + "no-descending-specificity": null, + "no-duplicate-selectors": null, + "scss/at-extend-no-missing-placeholder": null, + "scss/at-import-partial-extension": null, + "scss/at-import-no-partial-leading-underscore": null, + "scss/load-no-partial-leading-underscore": true, + "scss/at-mixin-pattern": null, + "scss/comment-no-empty": null, + "scss/dollar-variable-pattern": null, + "scss/double-slash-comment-whitespace-inside": null, + "scss/no-global-function-names": null, + "scss/operator-no-unspaced": null, + "selector-class-pattern": null, + "selector-id-pattern": null, + "liberty/use-logical-spec": "always" + } +} diff --git a/ui/cockpit-docker/HACKING.md b/ui/cockpit-docker/HACKING.md new file mode 100644 index 0000000..58a0898 --- /dev/null +++ b/ui/cockpit-docker/HACKING.md @@ -0,0 +1,107 @@ +# Hacking on Cockpit docker + +The commands here assume you're in the top level of the Cockpit docker git +repository checkout. + +## Running out of git checkout + +For development, you usually want to run your module straight out of the git +tree. To do that, run `make devel-install`, which links your checkout to the +location were `cockpit-bridge` looks for packages. If you prefer to do this +manually: + +``` +mkdir -p ~/.local/share/cockpit +ln -s `pwd`/dist ~/.local/share/cockpit/docker +``` + +After changing the code and running `make` again, reload the Cockpit page in +your browser. + +You can also use +[watch mode](https://esbuild.github.io/api/#watch) to +automatically update the bundle on every code change with + + $ make watch + +When developing against a virtual machine, watch mode can also automatically upload +the code changes by setting the `RSYNC` environment variable to +the remote hostname. + + $ RSYNC=c make watch + +When developing against a remote host as a normal user, `RSYNC_DEVEL` can be +set to upload code changes to `~/.local/share/cockpit/` instead of +`/usr/local`. + + $ RSYNC_DEVEL=example.com make watch + +## Running eslint + +Cockpit docker uses [ESLint](https://eslint.org/) to automatically check +JavaScript code style in `.jsx` and `.js` files. + +eslint is executed as part of `test/static-code`, aka. `make codecheck`. + +For developer convenience, the ESLint can be started explicitly by: + + $ npm run eslint + +Violations of some rules can be fixed automatically by: + + $ npm run eslint:fix + +Rules configuration can be found in the `.eslintrc.json` file. + +## Running stylelint + +Cockpit uses [Stylelint](https://stylelint.io/) to automatically check CSS code +style in `.css` and `scss` files. + +styleint is executed as part of `test/static-code`, aka. `make codecheck`. + +For developer convenience, the Stylelint can be started explicitly by: + + $ npm run stylelint + +Violations of some rules can be fixed automatically by: + + $ npm run stylelint:fix + +Rules configuration can be found in the `.stylelintrc.json` file. + +# Running tests locally + +Run `make vm` to build an RPM and install it into a standard Cockpit test VM. +This will be `fedora-39` by default. You can set `$TEST_OS` to use a different +image, for example + + TEST_OS=centos-8-stream make vm + +Then run + + make test/common + +to pull in [Cockpit's shared test API](https://github.com/cockpit-project/cockpit/tree/main/test/common) +for running Chrome DevTools Protocol based browser tests. + +With this preparation, you can manually run a single test without +rebuilding the VM, possibly with extra options for tracing and halting on test +failures (for interactive debugging): + + TEST_OS=... test/check-application TestApplication.testRunImageSystem -stv + +Use this command to list all known tests: + + test/check-application -l + +You can also run all of the tests: + + TEST_OS=centos-8-stream make check + +However, this is rather expensive, and most of the time it's better to let the +CI machinery do this on a draft pull request. + +Please see [Cockpit's test documentation](https://github.com/cockpit-project/cockpit/blob/main/test/README.md) +for details how to run against existing VMs, interactive browser window, +interacting with the test VM, and more. diff --git a/ui/cockpit-docker/LICENSE b/ui/cockpit-docker/LICENSE new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/ui/cockpit-docker/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ui/cockpit-docker/Makefile b/ui/cockpit-docker/Makefile new file mode 100644 index 0000000..af04f76 --- /dev/null +++ b/ui/cockpit-docker/Makefile @@ -0,0 +1,217 @@ +# extract name from package.json +PACKAGE_NAME := $(shell awk '/"name":/ {gsub(/[",]/, "", $$2); print $$2}' package.json) +RPM_NAME := cockpit-$(PACKAGE_NAME) +VERSION := $(shell T=$$(git describe --tags 2>/dev/null) || T=1; echo $$T | tr '-' '.') +ifeq ($(TEST_OS),) +TEST_OS = fedora-39 +endif +export TEST_OS +TARFILE=$(RPM_NAME)-$(VERSION).tar.xz +NODE_CACHE=$(RPM_NAME)-node-$(VERSION).tar.xz +SPEC=$(RPM_NAME).spec +PREFIX ?= /usr/local +APPSTREAMFILE=me.chabad360.$(PACKAGE_NAME).metainfo.xml +VM_IMAGE=$(CURDIR)/test/images/$(TEST_OS) +# stamp file to check for node_modules/ +NODE_MODULES_TEST=package-lock.json +# one example file in dist/ from bundler to check if that already ran +DIST_TEST=dist/manifest.json +# one example file in pkg/lib to check if it was already checked out +COCKPIT_REPO_STAMP=pkg/lib/cockpit-po-plugin.js +# common arguments for tar, mostly to make the generated tarballs reproducible +TAR_ARGS = --sort=name --mtime "@$(shell git show --no-patch --format='%at')" --mode=go=rX,u+rw,a-s --numeric-owner --owner=0 --group=0 + +VM_CUSTOMIZE_FLAGS = + +# HACK: https://github.com/containers/podman/issues/21896 +VM_CUSTOMIZE_FLAGS += --run-command 'nmcli con add type dummy con-name fake ifname fake0 ip4 1.2.3.4/24 gw4 1.2.3.1 >&2' + +# the following scenarios need network access +ifeq ("$(TEST_SCENARIO)","updates-testing") +VM_CUSTOMIZE_FLAGS += --run-command 'dnf -y update --setopt=install_weak_deps=False --enablerepo=updates-testing >&2' +else ifeq ("$(TEST_SCENARIO)","docker-next") +VM_CUSTOMIZE_FLAGS += --run-command 'dnf -y copr enable rhcontainerbot/docker-next >&2; dnf -y update --repo "copr*" >&2' +else +# default scenario does not install packages +VM_CUSTOMIZE_FLAGS += --no-network +endif + +ifeq ($(TEST_COVERAGE),yes) +RUN_TESTS_OPTIONS+=--coverage +NODE_ENV=development +endif + +all: $(DIST_TEST) + +# checkout common files from Cockpit repository required to build this project; +# this has no API stability guarantee, so check out a stable tag when you start +# a new project, use the latest release, and update it from time to time +COCKPIT_REPO_FILES = \ + pkg/lib \ + test/common \ + test/static-code \ + tools/node-modules \ + $(NULL) + +COCKPIT_REPO_URL = https://github.com/cockpit-project/cockpit.git +COCKPIT_REPO_COMMIT = d39255f6f768cc1c37a5786be8e8dc9d8f4d5ed2 # 315 + 83 commits + +$(COCKPIT_REPO_FILES): $(COCKPIT_REPO_STAMP) +COCKPIT_REPO_TREE = '$(strip $(COCKPIT_REPO_COMMIT))^{tree}' +$(COCKPIT_REPO_STAMP): Makefile + @git rev-list --quiet --objects $(COCKPIT_REPO_TREE) -- 2>/dev/null || \ + git fetch --no-tags --no-write-fetch-head --depth=1 $(COCKPIT_REPO_URL) $(COCKPIT_REPO_COMMIT) + git archive $(COCKPIT_REPO_TREE) -- $(COCKPIT_REPO_FILES) | tar x + +# +# i18n +# + +LINGUAS=$(basename $(notdir $(wildcard po/*.po))) + +po/$(PACKAGE_NAME).js.pot: + xgettext --default-domain=$(PACKAGE_NAME) --output=$@ --language=C --keyword= \ + --keyword=_:1,1t --keyword=_:1c,2,2t --keyword=C_:1c,2 \ + --keyword=N_ --keyword=NC_:1c,2 \ + --keyword=gettext:1,1t --keyword=gettext:1c,2,2t \ + --keyword=ngettext:1,2,3t --keyword=ngettext:1c,2,3,4t \ + --keyword=gettextCatalog.getString:1,3c --keyword=gettextCatalog.getPlural:2,3,4c \ + --from-code=UTF-8 $$(find src/ -name '*.js' -o -name '*.jsx') + +po/$(PACKAGE_NAME).html.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) + pkg/lib/html2po.js -o $@ $$(find src -name '*.html') + +po/$(PACKAGE_NAME).manifest.pot: $(NODE_MODULES_TEST) $(COCKPIT_REPO_STAMP) + pkg/lib/manifest2po.js src/manifest.json -o $@ + +po/$(PACKAGE_NAME).metainfo.pot: $(APPSTREAMFILE) + xgettext --default-domain=$(PACKAGE_NAME) --output=$@ $< + +po/$(PACKAGE_NAME).pot: po/$(PACKAGE_NAME).html.pot po/$(PACKAGE_NAME).js.pot po/$(PACKAGE_NAME).manifest.pot po/$(PACKAGE_NAME).metainfo.pot + msgcat --sort-output --output-file=$@ $^ + +po/LINGUAS: + echo $(LINGUAS) | tr ' ' '\n' > $@ + +# +# Build/Install/dist +# +$(SPEC): packaging/$(SPEC).in $(NODE_MODULES_TEST) + provides=$$(npm ls --omit dev --package-lock-only --depth=Infinity | grep -Eo '[^[:space:]]+@[^[:space:]]+' | sort -u | sed 's/^/Provides: bundled(npm(/; s/\(.*\)@/\1)) = /'); \ + awk -v p="$$provides" '{gsub(/%{VERSION}/, "$(VERSION)"); gsub(/%{NPM_PROVIDES}/, p)}1' $< > $@ + +packaging/arch/PKGBUILD: packaging/arch/PKGBUILD.in + sed 's/VERSION/$(VERSION)/; s/SOURCE/$(TARFILE)/' $< > $@ + +packaging/debian/changelog: packaging/debian/changelog.in + sed 's/VERSION/$(VERSION)/' $< > $@ + +$(DIST_TEST): $(COCKPIT_REPO_STAMP) $(shell find src/ -type f) package.json build.js + $(MAKE) package-lock.json && NODE_ENV=$(NODE_ENV) ./build.js + +watch: $(NODE_MODULES_TEST) + NODE_ENV=$(NODE_ENV) ./build.js -w + +clean: + rm -rf dist/ + rm -f $(SPEC) packaging/arch/PKGBUILD packaging/debian/changelog + rm -f po/LINGUAS + +install: $(DIST_TEST) po/LINGUAS + mkdir -p $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME) + cp -r dist/* $(DESTDIR)$(PREFIX)/share/cockpit/$(PACKAGE_NAME) + mkdir -p $(DESTDIR)$(PREFIX)/share/metainfo/ + msgfmt --xml -d po \ + --template $(APPSTREAMFILE) \ + -o $(DESTDIR)$(PREFIX)/share/metainfo/$(APPSTREAMFILE) + +# this requires a built source tree and avoids having to install anything system-wide +devel-install: $(DIST_TEST) + mkdir -p ~/.local/share/cockpit + ln -s `pwd`/dist ~/.local/share/cockpit/$(PACKAGE_NAME) + +# assumes that there was symlink set up using the above devel-install target, +# and removes it +devel-uninstall: + rm -f ~/.local/share/cockpit/$(PACKAGE_NAME) + +print-version: + @echo "$(VERSION)" + +# required for running integration tests; commander and ws are deps of chrome-remote-interface +TEST_NPMS = \ + node_modules/chrome-remote-interface \ + node_modules/commander \ + node_modules/sizzle \ + node_modules/ws \ + $(NULL) + +dist: $(TARFILE) + @ls -1 $(TARFILE) + +# when building a distribution tarball, call bundler with a 'production' environment by default +# we don't ship most node_modules for license and compactness reasons, only the ones necessary for running tests +# we ship a pre-built dist/ (so it's not necessary) and ship package-lock.json (so that node_modules/ can be reconstructed if necessary) +$(TARFILE): export NODE_ENV ?= production +$(TARFILE): $(DIST_TEST) $(SPEC) packaging/arch/PKGBUILD packaging/debian/changelog + if type appstream-util >/dev/null 2>&1; then appstream-util validate-relax --nonet *.metainfo.xml; fi + tar --xz $(TAR_ARGS) -cf $(TARFILE) --transform 's,^,$(RPM_NAME)/,' \ + --exclude '*.in' --exclude test/reference \ + $$(git ls-files | grep -v node_modules) \ + $(COCKPIT_REPO_FILES) $(NODE_MODULES_TEST) $(SPEC) $(TEST_NPMS) \ + packaging/arch/PKGBUILD packaging/debian/changelog dist/ + +# convenience target for developers +rpm: $(TARFILE) + rpmbuild -tb --define "_topdir $(CURDIR)/tmp/rpmbuild" $(TARFILE) + find tmp/rpmbuild -name '*.rpm' -printf '%f\n' -exec mv {} . \; + rm -r tmp/rpmbuild + +# build a VM with locally built distro pkgs installed +$(VM_IMAGE): $(TARFILE) packaging/debian/rules packaging/debian/control packaging/arch/PKGBUILD bots + # HACK for ostree images: skip the rpm build/install + if [ "$${TEST_OS%coreos}" != "$$TEST_OS" ] || [ "$${TEST_OS%bootc}" != "$$TEST_OS" ] || [ "$$TEST_OS" = "rhel4edge" ]; then \ + bots/image-customize --verbose --fresh --no-network --run-command 'mkdir -p /usr/local/share/cockpit' \ + --upload dist/:/usr/local/share/cockpit/docker \ + --script $(CURDIR)/test/vm.install $(TEST_OS); \ + else \ + bots/image-customize --verbose --fresh $(VM_CUSTOMIZE_FLAGS) --build $(TARFILE) \ + --script $(CURDIR)/test/vm.install $(TEST_OS); \ + fi + +# convenience target for the above +vm: $(VM_IMAGE) + @echo $(VM_IMAGE) + +# convenience target to print the filename of the test image +print-vm: + @echo $(VM_IMAGE) + +# run static code checks for python code +PYEXEFILES=$(shell git grep -lI '^#!.*python') + +codecheck: test/static-code $(NODE_MODULES_TEST) + test/static-code + +# convenience target to setup all the bits needed for the integration tests +# without actually running them +prepare-check: $(NODE_MODULES_TEST) $(VM_IMAGE) test/common test/reference + +# run the browser integration tests; skip check for SELinux denials +# this will run all tests/check-* and format them as TAP +check: prepare-check + TEST_AUDIT_NO_SELINUX=1 test/common/run-tests ${RUN_TESTS_OPTIONS} + +bots: $(COCKPIT_REPO_STAMP) + test/common/make-bots + +test/reference: test/common + test/common/pixel-tests pull + +# We want tools/node-modules to run every time package-lock.json is requested +# See https://www.gnu.org/software/make/manual/html_node/Force-Targets.html +FORCE: +$(NODE_MODULES_TEST): FORCE tools/node-modules + ./node-modules-fix.sh + +.PHONY: all clean install devel-install devel-uninstall print-version dist rpm prepare-check check vm print-vm diff --git a/ui/cockpit-docker/README.md b/ui/cockpit-docker/README.md new file mode 100644 index 0000000..cbab395 --- /dev/null +++ b/ui/cockpit-docker/README.md @@ -0,0 +1,86 @@ +# cockpit-docker + +This is the [Cockpit](https://cockpit-project.org/) user interface for [docker +containers](https://docker.io/). + +## Technologies + + - cockpit-docker communicates to docker through its [REST API](https://docs.docker.com/engine/api/v1.43/). + + - This project is based on [cockpit-podman](https://github.com/cockpit-project/cockpit-podman), I ported as much as I could to the docker API, but not everything maps (e.g. pods) and not everything is ported yet. + +# Development dependencies + +On Debian/Ubuntu: + + $ sudo apt install gettext nodejs make + +On Fedora: + + $ sudo dnf install gettext nodejs make + +# Getting and building the source + +These commands check out the source and build it into the `dist/` directory: + +``` +git clone https://github.com/cockpit-docker/cockpit-docker +cd cockpit-docker +make +``` + +# Installing + +`sudo make install` installs the package in `/usr/local/share/cockpit/`. This depends +on the `dist` target, which generates the distribution tarball. + +You can also run `make rpm` to build RPMs for local installation. + +In `production` mode, source files are automatically minified and compressed. +Set `NODE_ENV=production` if you want to duplicate this behavior. + +## Arch Derivatives +[AUR package](https://aur.archlinux.org/packages/cockpit-docker) + +`yay -Ss cockpit-docker` + +OR for Manjaro + +`pamac install cockpit-docker` + +# Development instructions + +See [HACKING.md](./HACKING.md) for details about how to efficiently change the +code, run, and test it. + +# Automated release + +The intention is that the only manual step for releasing a project is to create +a signed tag for the version number, which includes a summary of the noteworthy +changes: + +``` +123 + +- this new feature +- fix bug #123 +``` + +Pushing the release tag triggers the [release.yml](.github/workflows/release.yml) +[GitHub action](https://github.com/features/actions) workflow. This creates the +official release tarball and publishes as upstream release to GitHub. + +The Fedora and COPR releases are done with [Packit](https://packit.dev/), +see the [packit.yaml](./packit.yaml) control file. + +# Automated maintenance + +It is important to keep your [NPM modules](./package.json) up to date, to keep +up with security updates and bug fixes. This happens with +[dependabot](https://github.com/dependabot), +see [configuration file](.github/dependabot.yml). + +Translations are refreshed every Tuesday evening (or manually) through the +[weblate-sync-po.yml](.github/workflows/weblate-sync-po.yml) action. +Conversely, the PO template is uploaded to weblate every day through the +[weblate-sync-pot.yml](.github/workflows/weblate-sync-pot.yml) action. diff --git a/ui/cockpit-docker/build.js b/ui/cockpit-docker/build.js new file mode 100755 index 0000000..ba8f1d1 --- /dev/null +++ b/ui/cockpit-docker/build.js @@ -0,0 +1,108 @@ +#!/usr/bin/env node + +import fs from 'node:fs'; +import os from 'node:os'; + +import copy from 'esbuild-plugin-copy'; + +import { cockpitCompressPlugin } from './pkg/lib/esbuild-compress-plugin.js'; +import { cockpitPoEsbuildPlugin } from './pkg/lib/cockpit-po-plugin.js'; +import { cockpitRsyncEsbuildPlugin } from './pkg/lib/cockpit-rsync-plugin.js'; +import { cleanPlugin } from './pkg/lib/esbuild-cleanup-plugin.js'; +import { esbuildStylesPlugins } from './pkg/lib/esbuild-common.js'; + +const useWasm = os.arch() !== 'x64'; +const esbuild = (await import(useWasm ? 'esbuild-wasm' : 'esbuild')); + +const production = process.env.NODE_ENV === 'production'; +/* List of directories to use when resolving import statements */ +const nodePaths = ['pkg/lib']; +const outdir = 'dist'; + +// Obtain package name from package.json +const packageJson = JSON.parse(fs.readFileSync('package.json')); + +const parser = (await import('argparse')).default.ArgumentParser(); +parser.add_argument('-r', '--rsync', { help: "rsync bundles to ssh target after build", metavar: "HOST" }); +parser.add_argument('-w', '--watch', { action: 'store_true', help: "Enable watch mode", default: process.env.ESBUILD_WATCH === "true" }); +const args = parser.parse_args(); + +if (args.rsync) + process.env.RSYNC = args.rsync; + +function notifyEndPlugin() { + return { + name: 'notify-end', + setup(build) { + let startTime; + + build.onStart(() => { + startTime = new Date(); + }); + + build.onEnd(() => { + const endTime = new Date(); + const timeStamp = endTime.toTimeString().split(' ')[0]; + console.log(`${timeStamp}: Build finished in ${endTime - startTime} ms`); + }); + } + }; +} + +const context = await esbuild.context({ + ...!production ? { sourcemap: "linked" } : {}, + bundle: true, + entryPoints: ["./src/index.js"], + external: ['*.woff', '*.woff2', '*.jpg', '*.svg', '../../assets*'], // Allow external font files which live in ../../static/fonts + legalComments: 'external', // Move all legal comments to a .LEGAL.txt file + loader: { ".js": "jsx" }, + minify: production, + nodePaths, + outdir, + target: ['es2020'], + plugins: [ + cleanPlugin(), + // Esbuild will only copy assets that are explicitly imported and used + // in the code. This is a problem for index.html and manifest.json which are not imported + copy({ + assets: [ + { from: ['./src/manifest.json'], to: ['./manifest.json'] }, + { from: ['./src/index.html'], to: ['./index.html'] }, + ] + }), + ...esbuildStylesPlugins, + cockpitPoEsbuildPlugin(), + + ...production ? [cockpitCompressPlugin()] : [], + cockpitRsyncEsbuildPlugin({ dest: packageJson.name }), + + notifyEndPlugin(), + ] +}); + +try { + console.log(`Building ${production ? "for production" : "for dev"}...`); + await context.rebuild(); +} catch (e) { + if (!args.watch) + process.exit(1); + // ignore errors in watch mode +} + +if (args.watch) { + // Attention: this does not watch subdirectories -- if you ever introduce one, need to set up one watch per subdir + fs.watch('src', {}, async (ev, path) => { + // only listen for "change" events, as renames are noisy + if (ev !== "change") + return; + console.log("change detected:", path); + await context.cancel(); + try { + await context.rebuild(); + } catch (e) {} // ignore in watch mode + }); + // wait forever until Control-C + await new Promise(() => {}); +} + +context.dispose(); diff --git a/ui/cockpit-docker/me.chabad360.docker.metainfo.xml b/ui/cockpit-docker/me.chabad360.docker.metainfo.xml new file mode 100644 index 0000000..6725aad --- /dev/null +++ b/ui/cockpit-docker/me.chabad360.docker.metainfo.xml @@ -0,0 +1,16 @@ + + + me.chabad360.docker + CC0-1.0 + Docker + + Cockpit component for Docker containers + + +

+ The Cockpit user interface for Docker containers. +

+
+ org.cockpit_project.cockpit + docker +
diff --git a/ui/cockpit-docker/node-modules-fix.sh b/ui/cockpit-docker/node-modules-fix.sh new file mode 100755 index 0000000..05665ef --- /dev/null +++ b/ui/cockpit-docker/node-modules-fix.sh @@ -0,0 +1,9 @@ +tools/node-modules make_package_lock_json || ( \ + sed -i 's/local sha="${1-$(get_index_gitlink node_modules)}"/local sha="${2-$(get_index_gitlink node_modules)}"/' tools/node-modules && \ + tools/node-modules checkout --force && \ + sed -i 's/"name": "podman"/"name": "docker"/' node_modules/.package.json && \ + sed -i 's/"description": "Cockpit UI for Podman Containers"/"description": "Cockpit UI for Docker Containers"/' node_modules/.package.json && \ + sed -i 's/"repository": "git@github.com:cockpit-project\/cockpit-podman.git"/"repository": "https:\/\/github.com\/chabad360\/cockpit-docker.git"/' node_modules/.package.json && \ + sed -i 's/"name": "podman"/"name": "docker"/' node_modules/.package-lock.json && \ + tools/node-modules make_package_lock_json \ + ) \ No newline at end of file diff --git a/ui/cockpit-docker/package.json b/ui/cockpit-docker/package.json new file mode 100644 index 0000000..75b6130 --- /dev/null +++ b/ui/cockpit-docker/package.json @@ -0,0 +1,61 @@ +{ + "name": "docker", + "description": "Cockpit UI for Docker Containers", + "type": "module", + "main": "index.js", + "repository": "https://github.com/chabad360/cockpit-docker.git", + "author": "", + "license": "LGPL-2.1", + "scripts": { + "watch": "./build.js -w", + "build": "./build.js", + "eslint": "eslint --ext .jsx --ext .js src/", + "eslint:fix": "eslint --fix --ext .jsx --ext .js src/", + "stylelint": "stylelint src/*{.css,scss}", + "stylelint:fix": "stylelint --fix src/*{.css,scss}" + }, + "devDependencies": { + "argparse": "2.0.1", + "chrome-remote-interface": "^0.33.0", + "esbuild": "0.20.2", + "esbuild-plugin-copy": "2.1.1", + "esbuild-plugin-replace": "1.4.0", + "esbuild-sass-plugin": "3.2.0", + "esbuild-wasm": "0.20.2", + "eslint": "8.57.0", + "eslint-config-standard": "17.1.0", + "eslint-config-standard-jsx": "11.0.0", + "eslint-config-standard-react": "13.0.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "6.8.0", + "eslint-plugin-promise": "6.1.1", + "eslint-plugin-react": "7.34.1", + "eslint-plugin-react-hooks": "4.6.0", + "gettext-parser": "8.0.0", + "htmlparser": "1.7.7", + "jed": "1.1.1", + "sass": "1.75.0", + "sizzle": "2.3.10", + "stylelint": "16.4.0", + "stylelint-config-standard-scss": "13.1.0", + "stylelint-formatter-pretty": "4.0.0", + "stylelint-use-logical-spec": "5.0.1" + }, + "dependencies": { + "@patternfly/patternfly": "5.3.0", + "@patternfly/react-core": "5.3.0", + "@patternfly/react-icons": "5.3.0", + "@patternfly/react-styles": "5.3.0", + "@patternfly/react-table": "5.3.0", + "@patternfly/react-tokens": "5.3.0", + "date-fns": "3.6.0", + "docker-names": "1.2.1", + "ipaddr.js": "2.2.0", + "prop-types": "15.8.1", + "react": "18.2.0", + "react-dom": "18.2.0", + "throttle-debounce": "5.0.0", + "xterm": "5.1.0", + "xterm-addon-canvas": "0.4.0" + } +} diff --git a/ui/cockpit-docker/packaging/debian/control b/ui/cockpit-docker/packaging/debian/control new file mode 100644 index 0000000..f5590eb --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/control @@ -0,0 +1,22 @@ +Source: cockpit-docker +Section: admin +Priority: optional +Maintainer: Martin Pitt +Build-Depends: debhelper-compat (= 13), +Standards-Version: 4.6.2 +Rules-Requires-Root: no +Homepage: https://github.com/chabad360/cockpit-docker +Vcs-Git: https://github.com/chabad360/cockpit-docker.git +Vcs-Browser: https://github.com/chabad360/cockpit-docker + +Package: cockpit-docker +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends}, + cockpit-bridge, + docker (>= 24), +Description: Cockpit component for docker containers + The Cockpit Web Console enables users to administer GNU/Linux servers using a + web browser. + . + This package adds an user interface for docker containers. diff --git a/ui/cockpit-docker/packaging/debian/copyright b/ui/cockpit-docker/packaging/debian/copyright new file mode 100644 index 0000000..7262793 --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/copyright @@ -0,0 +1,38 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: cockpit-docker +Source: https://github.com/chabad360/cockpit-docker +Comment: + This does not directly cover the files in dist/*. These are "minified" and + compressed JavaScript/HTML files built from src/, lib/, po/, and node_modules/ + with node, npm, and a bundler. node_modules/ is not shipped as part of the + upstream release tarballs, but can be reconstructed precisely through the + shipped package-lock.json with the command "npm install". Rebuilding files in + dist/ requires internet access as that process needs to download additional + npm modules from the Internet, thus upstream ships the pre-minified bundles + as part of the upstream release tarball so that the package can be built + without internet access and lots of extra unpackaged build dependencies. + +Files: * +Copyright: 2016-2020 Red Hat, Inc and 2023 Jewish Education Media. +License: LGPL-2.1 + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see . + . + On Debian systems, the complete text of the GNU Lesser General + Public License can be found in "/usr/share/common-licenses/LGPL-2.1". + +Files: *.metainfo.xml +Copyright: Copyright (C) 2018 Red Hat, Inc and 2023 Jewish Education Media. +License: CC0-1.0 + On Debian systems, the complete text of the Creative Commons Zero v1.0 + Universal Public License is in "/usr/share/common-licenses/LGPL-2.1". diff --git a/ui/cockpit-docker/packaging/debian/rules b/ui/cockpit-docker/packaging/debian/rules new file mode 100755 index 0000000..c349516 --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/rules @@ -0,0 +1,13 @@ +#!/usr/bin/make -f + +export PREFIX=/usr + +%: + dh $@ + +override_dh_auto_clean: + # don't call `make clean`, in a release dist/ is precious + rm -f po/LINGUAS + +override_dh_auto_test: + # don't call `make check`, these are integration tests diff --git a/ui/cockpit-docker/packaging/debian/source/format b/ui/cockpit-docker/packaging/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/ui/cockpit-docker/packaging/debian/source/lintian-overrides b/ui/cockpit-docker/packaging/debian/source/lintian-overrides new file mode 100644 index 0000000..c8c9e0d --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/source/lintian-overrides @@ -0,0 +1,2 @@ +# source contains NPM modules required for running browser integration tests +cockpit-docker source: source-is-missing *node_modules/* diff --git a/ui/cockpit-docker/packaging/debian/upstream/metadata b/ui/cockpit-docker/packaging/debian/upstream/metadata new file mode 100644 index 0000000..29a8d5c --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/upstream/metadata @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/chabad360/cockpit-docker/issues +Bug-Submit: https://github.com/chabad360/cockpit-docker/issues/new +Repository-Browse: https://github.com/chabad360/cockpit-docker diff --git a/ui/cockpit-docker/packaging/debian/watch b/ui/cockpit-docker/packaging/debian/watch new file mode 100644 index 0000000..9820c0a --- /dev/null +++ b/ui/cockpit-docker/packaging/debian/watch @@ -0,0 +1,5 @@ +version=4 +opts="searchmode=plain, \ +filenamemangle=s/.+\/@PACKAGE@-@ANY_VERSION@.tar.gz/@PACKAGE@-$1\.tar\.xz/" \ +https://api.github.com/repos/cockpit-chabad360/@PACKAGE@/releases \ +https://github.com/cockpit-chabad360/@PACKAGE@/releases/download/\d[\.\d]*/@PACKAGE@-@ANY_VERSION@.tar.xz diff --git a/ui/cockpit-docker/packit.yaml b/ui/cockpit-docker/packit.yaml new file mode 100644 index 0000000..2597a21 --- /dev/null +++ b/ui/cockpit-docker/packit.yaml @@ -0,0 +1,80 @@ +upstream_project_url: https://github.com/chabad360/cockpit-docker +# enable notification of failed downstream jobs as issues +issue_repository: https://github.com/chabad360/cockpit-docker +specfile_path: cockpit-docker.spec +upstream_package_name: cockpit-docker +downstream_package_name: cockpit-docker +# use the nicely formatted release description from our upstream release, instead of git shortlog +copy_upstream_release_description: true + +actions: + post-upstream-clone: make cockpit-docker.spec + create-archive: make dist + +srpm_build_deps: + - make + - npm + +jobs: + - job: copr_build + trigger: pull_request + targets: + - fedora-39 + - fedora-40 + - fedora-latest-aarch64 + - fedora-development + - centos-stream-9-x86_64 + - centos-stream-9-aarch64 + - centos-stream-8-x86_64 + + - job: tests + trigger: pull_request + targets: + - fedora-39 + - fedora-40 + - fedora-latest-aarch64 + - fedora-development + - centos-stream-9-x86_64 + - centos-stream-9-aarch64 + - centos-stream-8-x86_64 + + - job: copr_build + trigger: release + owner: "@cockpit" + project: "cockpit-preview" + preserve_project: True + actions: + post-upstream-clone: make cockpit-docker.spec + # HACK: tarball for releases (copr_build, koji, etc.), copying spec's Source0; this + # really should be the default, see https://github.com/packit/packit-service/issues/1505 + create-archive: + - sh -exc "curl -L -O https://github.com/chabad360/cockpit-docker/releases/download/${PACKIT_PROJECT_VERSION}/${PACKIT_PROJECT_NAME_VERSION}.tar.xz" + - sh -exc "ls ${PACKIT_PROJECT_NAME_VERSION}.tar.xz" + + - job: copr_build + trigger: commit + branch: "^main$" + owner: "@cockpit" + project: "main-builds" + preserve_project: True + + - job: propose_downstream + trigger: release + dist_git_branches: + - fedora-development + - fedora-39 + - fedora-40 + + - job: koji_build + trigger: commit + dist_git_branches: + - fedora-development + - fedora-39 + - fedora-40 + + - job: bodhi_update + trigger: commit + dist_git_branches: + # rawhide updates are created automatically + - fedora-39 + - fedora-40 diff --git a/ui/cockpit-docker/plans/all.fmf b/ui/cockpit-docker/plans/all.fmf new file mode 100644 index 0000000..1529147 --- /dev/null +++ b/ui/cockpit-docker/plans/all.fmf @@ -0,0 +1,23 @@ +discover: + how: fmf +execute: + how: tmt + +# Let's handle them upstream only, don't break Fedora/RHEL reverse dependency gating +environment: + TEST_AUDIT_NO_SELINUX: 1 + +/system: + summary: Run tests on system docker + discover+: + test: /test/browser/system + +/user: + summary: Run tests on user docker + discover+: + test: /test/browser/user + +/misc: + summary: Run other tests + discover+: + test: /test/browser/other diff --git a/ui/cockpit-docker/po/cs.po b/ui/cockpit-docker/po/cs.po new file mode 100644 index 0000000..48d63a2 --- /dev/null +++ b/ui/cockpit-docker/po/cs.po @@ -0,0 +1,1510 @@ +# Pavel Borecki , 2019. #zanata, 2020. +# Matej Marusak , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-11-29 13:31+0000\n" +"Last-Translator: Pavel Borecki \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" +"X-Generator: Weblate 5.2.1\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 kontejner" +msgstr[1] "$0 kontejnery" +msgstr[2] "$0 kontejnerů" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 obraz celkem, $1" +msgstr[1] "$0 obrazy celkem, $1" +msgstr[2] "$0 obrazů celkem, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 sekunda" +msgstr[1] "$0 sekundy" +msgstr[2] "$0 sekund" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 nepoužitý obraz, $1" +msgstr[1] "$0 nepoužité obrazy, $1" +msgstr[2] "$0 nepoužitých obrazů, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 až 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" +"Akce kterou podniknout jakmile kontejner přejde do stavu, kdy nebude v " +"pořádku." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Přidat mapování portů" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Přidat proměnnou prostředí" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Přidat svazek" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Vše" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Všechny registry" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Vždy" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Došlo k chybě" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Autor" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Docker spouštět automaticky při zavádění systému" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "Procesor" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Nápověda ke sdílení procesoru" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Sdílení procesoru" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"Sdílení procesoru určuje prioritu spuštěných kontejnerů. Výchozí priorita je " +"1024. Vyšší číslo upřednostňuje tento kontejner. Nižší číslo jeho přednost " +"snižuje." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Storno" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Kontroluje se stav" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Kontrolní bod" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Kontrolní bod a podpora obnovení" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Kontejner kontrolního bodu $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Kliknutím zobrazíte publikované porty" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Kliknutím zobrazíte svazky" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Součást Cockpit pro Docker kontejnery" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Příkaz" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Komentáře" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Odeslat" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Odeslat kontejner" + +#: src/util.js:23 +msgid "Configured" +msgstr "Nastaveno" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konzole" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Kontejner" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Kontejner se nepodařilo vytvořit" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Kontejner se nepodařilo spustit" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Kontejner není spuštěný" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Název kontejneru" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Je třeba zadat název kontejneru." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Popis umístění kontejneru" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "Je třeba vyplnit popis umístění kontejneru" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Port kontejneru" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "Je třeba vyplnit port kontejneru" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Kontejnery" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Vytvořit" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Vytvořit nový obraz založený na stávajícím stavu kontejneru $0." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Vytvořit a spustit" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Vytvořit kontejner" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Vytvořit kontejner v $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Vytvořit kontejner v podu" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Vytvořit pod" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Vytvořeno" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Vytvořil" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Snížit podíl na procesoru" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Snížit interval" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Snížit limit počtu opětovných pokusů" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Zmenšit paměť" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Snížit počet opakovaných pokusů" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Snížit periodu startu" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Snížit časový limit" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Smazat" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "Smazat obraz $0?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Smazat $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Smazat obraz" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Smazat pod $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Smazat značkou označené obrazy" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Smazat nepoužívané systémové obrazy:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Smazat nepoužívané uživatelské obrazy:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Smazání kontejneru smaže veškerá data v něm." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "Smazání spuštěného kontejneru smaže veškerá data v něm." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Smazání tohoto podu odebere následující kontejnery:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Podrobnosti" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Prostor na disku" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "Formát Docker se hodí pro sdílení obrazu s enginem Docker nebo Moby" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Stáhnout" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Stáhnout si nový obraz" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Prázdný pod $0 bude nenávratně odebrán." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Vstupní bod" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Proměnné prostředí" + +#: src/util.js:26 +msgid "Error" +msgstr "Chyba" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Chybové hlášení" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Nastala chyba při připojování ke konzoli" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Příklad, vaše jméno " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Příklad: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Skončilo" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Nepodařilo se spustit kontrolu vitálnosti" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Kontejner $0 se nepodařilo opatřit kontrolním bodem" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Nepodařilo se vyčistit kontejner" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Nepodařilo se odeslat kontejner $0" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Nepodařilo se vytvořit kontejner $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Nepodařilo se stáhnout obraz $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Nepodařilo se vynutit odebrání kontejneru $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Nepodařilo se vynutit odebrání obrazu $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Nepodařilo se vynutit restart podu $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Nepodařilo se vynutit zastavení podu $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Nepodařilo se pozastavit kontejner $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Nepodařilo se pozastavit pod $0" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Nepodařilo se prořezat nepoužívané kontejnery" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Nepodařilo se prořezat nepoužívané obrazy" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Nepodařilo se odeslat obraz $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Nepodařilo se odebrat kontejner $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Nepodařilo se odebrat obraz $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Nepodařilo se přejmenovat kontejner $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Nepodařilo se restartovat kontejner $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Nepodařilo se restartovat pod $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Nepodařilo se obnovit kontejner $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Nepodařilo se navázat v chodu kontejneru $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Nepodařilo se navázat v chodu podu $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Nepodařilo se spustit kontejner $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Nepodařilo se zkontrolovat vitálnost kontejneru $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Nepodařilo se vyhledat obrazy." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Nepodařilo se vyhledat obrazy: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Nepodařilo se vyhledat nové obrazy" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Nepodařilo se spustit kontejner $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Nepodařilo se spustit pod $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Nepodařilo se zastavit kontejner $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Nepodařilo se zastavit pod $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Selhávající streak" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Vynutit odeslání" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Vynutit smazání" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Vynutit smazání podu $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Vynutit restart" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Vynutit zastavení" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Brána" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Kontrola vitálnosti" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Nápověda k intervalu kontroly vitálnosti" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Nápověda k opakovaným pokusům o kontrolu vitálnosti" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Nápověda k periodě startu kontroly vitálnosti" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Nápověda k časovému limitu kontroly vitálnosti" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Nápověda k akci kontroly selhání" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "V pořádku" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Skrýt obrazy" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Skrýt obrazy mezi tím" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historie" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Popis umístění hostitele" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Port hostitele" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Nápověda k portu hostitele" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "Identif." + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP adresa" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Nápověda k IP adrese" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Ideální pro vývoj" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Ideální pro provozování služeb" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Pokud je IP adresa hostitele nastavena na 0.0.0.0 nebo vůbec nenastavena, " +"port bude navázán na všechny IP adresy hostitele." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Pokud port hostitele není nastavený, port kontejneru bude náhodně přiřazen " +"na port hostitele." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Pokud je nastavená staticky, IP adresu ignorovat" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Pokud je nastavená staticky, MAC adresu ignorovat" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Obraz" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Název obrazu už je použit" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Je třeba zadat název obrazu" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Nápověda k výběru obrazu" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Obrazy" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Zvýšit podíl na procesoru" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Prodloužit interval" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Zvýšit počet opětovných pokusů" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Zvětšit paměť" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Zvýšit počet opakování pokusů" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Zvýšit periodu startu" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Prodloužit časový limit" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Napojení" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Interval" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Jak často spouštět kontrolu vitálnosti." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Neplatné znaky. Název může obsahovat pouze písmena, číslice a vybranou " +"interpunkci (_.-)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Ponechat všechny dočasné soubory kontrolních bodů" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Klíč" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "Je třeba vyplnit klíč" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Minulých 5 spuštění" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Nejnovější kontrolní bod" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Po zapsání kontrolního bodu na disk ponechat spuštěné" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Načítání podrobností…" + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Načítání záznamů událostí…" + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Načítání…" + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Lokální" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Lokální obrazy" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Záznamy událostí" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC adresa" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Maximální počet opětovných pokusů" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Operační paměť" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Limit operační paměti" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Jednotka operační paměti" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Režim" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Pro tento obraz existuje vícero štítků. Vyberte oštítkované obrazy, které " +"smazat." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "Je třeba, aby byla platná IP adresa" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Název" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Název je už používán" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Nový název pro kontejner" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Název nového obrazu" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Ne" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Žádná akce" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Žádné kontejnery" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Tento obraz není používán žádným kontejnerem" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "V tomto podu nejsou žádné kontejnery" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Stávajícímu filtru neodpovídají žádné kontejnery" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Nezadány žádné proměnné prostředí" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Žádné obrazy" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Nenalezeny žádné obrazy" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Žádné obrazy které by odpovídaly stávajícímu filtru" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Žádný štítek" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Nejsou vystavené žádné porty" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Žádné výsledky pro $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Žádné spuštěné kontejnery" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Nejsou určeny žádné svazky" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Při nezdaru" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Pouze spuštěné" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Volby" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Vlastník" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Nápověda k vlastníkovi" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Prošlo kontrolou vitálnosti" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Pokud chcete hromadně naimportovat, zadejte do libovolné kolonky jeden či " +"více řádků s dvojicemi klíč=hodnota" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Pozastavit" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Při vytváření obrazu pozastavit kontejner" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Pozastaveno" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Pod se nepodařilo vytvořit" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Název pro pod" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker kontejnery" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Služba docker není aktivní" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Mapování portů" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Porty" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Je možné mapovat porty do čísla 1024" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Soukromé" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokol" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Prořezat" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Prořezat nepoužívané kontejnery" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Prořezat nepoužívané obrazy" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Prořezávání kontejnerů" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Prořezávají se obrazy" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Stáhnout si nejnovější obraz" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Stahování" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Přístup pouze pro čtení" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Přístup pro čtení i zápis" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Odebrat položku" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Odebere označené (a nespuštěné) kontejnery" + +#: src/util.js:23 +msgid "Removing" +msgstr "Odebírá se" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Přejmenovat" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Přejmenovat kontejner $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Je možné nastavit limity prostředků" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Restart" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Pravidlo restartování" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Nápověda k pravidlu restartování" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "" +"Které pravidlo ohledně restartování následovat když se kontejnery ukončují." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Pravidlo ohledně restartování kterým se řídit při ukončení kontejnerů. Pokud " +"je v rámci uživatelského účtu používán např. ecryptfs, systemd-homed, NFS " +"nebo 2FA, pak se může stávat, že automatické spouštění pomocí linger za " +"určitých podmínek nemusí zafungovat." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Obnovit" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Obnovit kontejner $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Obnovit s navázanými TCP spojeními" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Omezeno oprávněními uživatelského účtu" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Navázat v chodu" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Opětovných pokusů" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Zkusit znovu jiný pojem." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Zkontrolovat vitálnost" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Spuštěné" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Hledat podle názvu nebo popisu" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Hledat podle registru (repozitáře)" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Hledat" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Hledat obraz" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Hledat řetězec nebo umístění kontejneru" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Vyhledávání..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Vyhledávání: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Sdílené" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Zobrazit" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Zobrazit obrazy" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Zobrazit obrazy mezi tím" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Zobrazit méně" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Zobrazit více" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Velikost" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Spustit" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Perioda startu" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Spustit docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Vyhledávání obrazů zahájíte psaním." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Spuštěno v" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Stav" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Stav" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Zastavit" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Zastaveno" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Podpora pro zachování navázaných TCP spojení" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Systém" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Je také k dispozici systémová služba Docker" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Štítek" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Štítky" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Cockpit uživatelské rozhraní pro Docker kontejnery." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Doba potřebná pro inicializaci zavádění kontejneru." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Nejdelší přijatelná doba pro dokončení kontroly vitálnosti, než bude " +"interval považován za nezdařilý." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Umožněný počet opětovných pokusů než bude výsledek kontroly vitálnosti " +"považován za negativní." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Časový limit" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Řešení problémů" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Filtrujte psaním…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Nepodařilo se načíst historii obrazu" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Není v pořádku" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "V chodu od $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Použít původní Docker formát" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Používáno" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Uživatel" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Je také k dispozici uživatelská služba Docker" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Uživatel:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Hodnota" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Svazky" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Pokud v nepořádku" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "S terminálem" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Zapisovatelné" + +#: src/manifest.json:0 +msgid "container" +msgstr "kontejner" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "stahuje se" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "hostitel[:port]/[uživatel]/kontejner[:štítek]" + +#: src/manifest.json:0 +msgid "image" +msgstr "obraz" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "v" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "mezi tím" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "Obraz mezi tím" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "n/a" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "není k dispozici" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "skupina podu" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "porty" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "sekund" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "systém" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "nepoužito" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "uživatel:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "svazky" + +#~ msgid "Delete $0" +#~ msgstr "Smazat $0" + +#~ msgid "select all" +#~ msgstr "vybrat vše" + +#~ msgid "Failure action" +#~ msgstr "Akce při selhání" + +#~ msgid "Restarting" +#~ msgstr "Restartuje se" + +#, fuzzy +#~| msgid "Please confirm deletion of $0" +#~ msgid "Confirm deletion of $0" +#~ msgstr "Potvrďte smazání $0" + +#, fuzzy +#~| msgid "Please confirm deletion of pod $0" +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Potvrďte smazání podu $0" + +#, fuzzy +#~| msgid "Please confirm force deletion of pod $0" +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Potvrďte vynucení smazání podu $0" + +#, fuzzy +#~| msgid "Please confirm forced deletion of $0" +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Potvrďte vynucení smazání $0" + +#~ msgid "Container is currently running." +#~ msgstr "Kontejner je nyní spuštěný." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Do exportu nezahrnovat změny v kořenovém souborovém systému" + +#~ msgid "Default with single selectable" +#~ msgstr "Výchozí s jedním k výběru" + +#~ msgid "Start after creation" +#~ msgstr "Po vytvoření spustit" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Smazat nepoužité $0 obrazy:" + +#~ msgid "created" +#~ msgstr "vytvořeno" + +#~ msgid "exited" +#~ msgstr "skončilo" + +#~ msgid "paused" +#~ msgstr "pozastaveno" + +#~ msgid "running" +#~ msgstr "spuštěné" + +#~ msgid "stopped" +#~ msgstr "zastaveno" + +#~ msgid "user" +#~ msgstr "uživatel" + +#~ msgid "Add on build variable" +#~ msgstr "Přídatná proměnná prostředí" + +#~ msgid "Commit image" +#~ msgstr "Odeslat obraz" + +#~ msgid "Format" +#~ msgstr "Formát" + +#~ msgid "Message" +#~ msgstr "Zpráva" + +#~ msgid "Pause the container" +#~ msgstr "Pozastavit kontejner" + +#~ msgid "Remove on build variable" +#~ msgstr "Odebrat na proměnných prostředí" + +#~ msgid "Set container on build variables" +#~ msgstr "Nastavit kontejner na proměnných prostředí" + +#~ msgid "Add item" +#~ msgstr "Přidat položku" + +#~ msgid "Host port (optional)" +#~ msgstr "Port hostitele (volitelně)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (volitelně)" + +#~ msgid "ReadOnly" +#~ msgstr "PouzeProČtení" + +#~ msgid "IP prefix length" +#~ msgstr "Délka přepony IP adresy" + +#~ msgid "Get new image" +#~ msgstr "Získat nový obraz" + +#~ msgid "Run" +#~ msgstr "Spustit" + +#~ msgid "On build" +#~ msgstr "Při sestavení" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Opravdu chcete tento obraz smazat?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Nedaří se připojit k tomuto kontejneru: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Nedaří se otevřít kanál:$0" + +#~ msgid "Everything" +#~ msgstr "Vše" + +#~ msgid "Security" +#~ msgstr "Zabezpečení" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "Sken z $time ($type) nenalezl žádné zranitelnosti." + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "Tato verze Web Console nepodporuje terminál." diff --git a/ui/cockpit-docker/po/de.po b/ui/cockpit-docker/po/de.po new file mode 100644 index 0000000..8f9dc55 --- /dev/null +++ b/ui/cockpit-docker/po/de.po @@ -0,0 +1,1505 @@ +# Martin Pitt , 2019. #zanata +# Mike FABIAN , 2020. +# Matej Marusak , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-09-02 07:21+0000\n" +"Last-Translator: Martin Pitt \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 4.18.2\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 Container" +msgstr[1] "$0 Container" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 Abbild insgesamt, $1" +msgstr[1] "$0 Abbilder insgesamt, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 Sekunde" +msgstr[1] "$0 Sekunden" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 ungenutztes Abbild, $1" +msgstr[1] "$0 ungenutzte Abbilder, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" +"Zu ergreifende Maßnahmen, wenn der Container in einen ungesunden Zustand " +"übergeht." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Port-Zuordnung hinzufügen" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Variable hinzufügen" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Volumen hinzufügen" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Alle" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Alle Registries" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Immer" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Ein Fehler ist aufgetreten" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Autor" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Docker automatisch beim Hochfahren starten" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU Shares Hilfe" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU-Shares" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU Shares legt die Priorität laufender Container fest. Standardwert ist " +"1024. Ein höherer Wert priorisiert den Container. Ein niedrigerer Wert senkt " +"dessen Priorität." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Abbruch" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Überprüfung der Gesundheit" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Kontrollpunkt" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Unterstützung von Kontrollpunkten und Wiederherstellung" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Kontrollpunkt für Container $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Klicken um veröffentlichte Ports zu sehen" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Klicken um Volumen zu sehen" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Cockpit Bestandteil für Docker-Container" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Befehl" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Kommentare" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Committen" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Container übergeben" + +#: src/util.js:23 +msgid "Configured" +msgstr "Konfiguriert" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konsole" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Container" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Container konnte nicht erstellt werden" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Container konnte nicht erstellt werden" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Container läuft nicht" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Container-Name" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Containername ist erforderlich." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Container-Pfad" + +#: src/Volume.jsx:23 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container path must not be empty" +msgstr "Container konnte nicht erstellt werden" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Container-Port" + +#: src/PublishPort.jsx:37 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container port must not be empty" +msgstr "Container konnte nicht erstellt werden" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Container" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Erstellen" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "" +"Ein neues Abbild auf der Grundlage des aktuellen Zustands des Containers $0 " +"erstellen." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Erstellen und ausführen" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Container erstellen" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Container in $0 erstellen" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Container in Pod erstellen" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Pod erstellen" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Erstellt" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Erstellt von" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "CPU-Anteile verringern" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Intervall verringern" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Maximale Wiederholungsversuche verringern" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Speicher verringern" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Wiederholungsversuche verringern" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Startzeitraum verringern" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Zeitüberschreitung verringern" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Löschen" + +#: src/ImageDeleteModal.jsx:92 +#, fuzzy +#| msgid "Delete $0?" +msgid "Delete $0 image?" +msgstr "$0 löschen?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "$0 löschen?" + +#: src/ImageDeleteModal.jsx:96 +#, fuzzy +#| msgid "Delete tagged images" +msgid "Delete image" +msgstr "Markierte Image löschen" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Pod $0 löschen?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Markierte Image löschen" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Nicht verwendete Systemabbilder löschen:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Nicht verwendete Benutzerabbilder löschen:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Beim Löschen des Containers werden alle Daten darin verloren gehen." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "" +"Das Löschen eines laufenden Containers führt dazu, dass alle darin " +"enthaltenen Daten gelöscht werden." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Löschen des Pods wird die folgenden Container entfernen:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Details" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Speicherplatz" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Docker-Format ist hilfreich, wenn das Image mit Docker oder Moby Engine " +"geteilt wird" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Herunterladen" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Neues Abbild herunterladen" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Leerer Pod $0 wird endgültig entfernt." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Einsprungspunkt" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Umgebungsvariablen" + +#: src/util.js:26 +msgid "Error" +msgstr "Fehler" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Fehlermeldung" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Beim Verbinden der Konsole ist ein Fehler aufgetreten" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Beispiel, Ihr Name " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Beispiel: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Beendet" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Gesundheitsprüfung fehlgeschlagen" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Überprüfung von Container $0 fehlgeschlagen" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Fehler bei der Bereinigung des Containers" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Konnte Container $0 nicht committen" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Fehler bei der Erstellung des Containers $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Konnte Image $0 nicht herunterladen: $1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Konnte Container $0 nicht neu entfernen" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Fehler bei der erzwungenen Entfernung des Abbilds $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Konnte Pod $0 nicht neu starten" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Konnte Pod $0 nicht stoppen" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Konnte Container $0 nicht pausieren" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Konnte Pod $0 nicht pausieren" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Löschen nicht gebrauchter Container fehlgeschlagen" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Reduzierung nicht gebrauchter Abbilder fehlgeschlagen" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Image $0 konnte nicht gepullt werden" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Konnte Container $0 nicht neu entfernen" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Fehler bei der Entfernung von Abbild $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Fehler beim Umbenennen des Containers $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Konnte Container $0 nicht neu starten" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Konnte Pod $0 nicht neu starten" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Konnte Container $0 nicht wiederherstellen" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Konnte Container $0 nicht wieder starten" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Konnte Pod $0 nicht wieder starten" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Konnte Container $0 nicht starten" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Gesundheitsprüfung von Container $0 fehlgeschlagen" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Konnte nicht nach Images suchen." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Konnte nicht nach Images suchen: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Konnte nicht nach neuen Images suchen" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Konnte Container $0 nicht starten" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Konnte Pod $0 nicht starten" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Konnte Container $0 nicht stoppen" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Konnte Pod $0 nicht stoppen" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Übergabe erzwingen" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Löschen erzwingen" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Löschen von Pod $0 erzwingen?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Neustart erzwingen" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Stoppen erzwingen" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Gateway" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Gesundheitsprüfung" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Hilfe zum Gesundheitsprüfungsintervall" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Hilfe zur Wiederholung der Gesundheitsprüfung" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Hilfe zur Periode der Gesundheitsprüfung" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Hilfe zum Zeitlimit der Gesundheitsprüfung" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Hilfe zur Gesundheitsprüfungs-Aktion" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Gesund" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Abbilder ausblenden" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Intermediate Images verstecken" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Verlauf" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Host-Pfad" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Host-Port" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Hilfe zum Host-Port" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP-Adresse" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Hilfe zur IP-Adresse" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Ideal zur Entwicklung" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Ideal für Dienste" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Wenn die Host-IP auf 0.0.0.0 oder gar nicht gesetzt ist, wird der Port an " +"alle IPs des Hosts gebunden." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Wenn der Host-Port nicht gesetzt ist, wird dem Container-Port ein zufälliger " +"Port auf dem Host zugewiesen." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "IP-Adresse ignorieren, wenn statisch festgelegt" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "MAC-Adresse ignorieren, wenn statisch festgelegt" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Image" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Abbildname ist nicht eindeutig" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Abbildname ist erforderlich" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Abbildauswahl-Hilfe" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Images" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "CPU-Anteile erhöhen" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Intervall erhöhen" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Maximale Wiederholungsversuche erhöhen" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Speicher erhöhen" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Wiederholungsversuche erhöhen" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Startzeitraum erhöhen" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Zeitüberschreitung erhöhen" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integration" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Intervall" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Intervall, in dem die Gesundheitsprüfung durchgeführt wird." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Ungültige Zeichen. Der Name darf nur Buchstaben, Zahlen und bestimmte " +"Satzzeichen (_ . -) enthalten." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Alle temporären Kontrollpunktdateien behalten" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Schlüssel" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Letzte 5 Durchläufe" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "LetzterKontrollpunkt" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "" +"Nach dem Schreiben des Kontrollpunkts auf die Festplatte weiterlaufen lassen" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Details werden geladen ..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Protokolle werden geladen ..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Wird geladen ..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Lokal" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Lokale Abbilder" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Protokolle" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC-Adresse" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Maximale Versuche" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Speicher" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Speicher-Limit" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Speichereinheit" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Modus" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Mehrere Tags für dieses Image vorhanden. Getagte Images zum Löschen " +"auswählen." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Name" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Neuer Containername" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Neuer Abbildname" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Nein" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Keine Aktion" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Keine Container" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Keine Container benutzen dieses Abbild" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Keine Container in diesem Pod" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Aktueller Filter passt auf keinen Container" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Keine Umgebungsvariablen angegeben" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Keine Images" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Keine Abbilder gefunden" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Aktueller Filter passt auf kein Image" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Keine Bezeichnung" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Keine offenen Ports" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Keine Ergebnisse für $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Keine laufenden Container" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Keine Volumen angegeben" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Bei einem Ausfall" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Nur laufenlassen" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Optionen" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Eigentümer" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Eigentümer-Hilfe" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Bestandener Gesundheitstest" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Fügen Sie eine oder mehrere Zeilen mit key=value Paaren in irgendein Feld " +"ein für multiplen Import" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Anhalten" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Container bei der Abbilderstellung pausieren" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Pausiert" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Pod konnte nicht erstellt werden" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Pod-Name" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker-Container" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker-Service ist nicht aktiv" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Portzuordnung" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Ports" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Privat" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokoll" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Reduzieren" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Nicht benötigte Abbilder löschen" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Reduzierung nicht benötigter Abbilder" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Räume Container auf" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Reduziere Abbilder" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Neuestes Image pullen" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Herunterladen" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Nur-Lese-Zugriff" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Lese-/Schreibzugriff" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Element entfernen" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Entfernt selektierte nicht-laufende Container" + +#: src/util.js:23 +msgid "Removing" +msgstr "Wird entfernt" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Umbenennen" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Container $0 umbenennen" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Ressourcen-Grenzen können gesetzt werden" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Neustart" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Neustartrichtlinie" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Neustartrichtlinien-Hilfe" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "" +"Neustart-Richtlinie, die beim Beenden von Containern befolgt werden soll." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Wiederherstellen" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Container $0 wiederherstellen" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Wiederherstellung mit bestehenden TCP-Verbindungen" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Eingeschränkt durch Benutzerkonto-Privilegien" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Fotfahren" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Wiederholungsversuche" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Versuchen Sie einen anderen Begriff." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Gesundheitsprüfung durchführen" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Läuft" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Nach Name oder Beschreibung suchen" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Nach Registry suchen" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Suchen nach" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Nach einem Abbild suchen" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Suchbegriff oder Containerort" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Wird gesucht ..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Wird gesucht: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Freigegeben" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Anzeigen" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Abbilder anzeigen" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Zwischenabbilder anzeigen" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Weniger anzeigen" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Mehr anzeigen" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Größe" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Starten" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Startzeitraum" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Docker starten" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Zum Suchen nach Abbildern mit dem Tippen beginnen." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Gestartet am" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Zustand" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Status" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Stoppen" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Angehalten" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Unterstützung der Aufrechterhaltung bestehender TCP-Verbindungen" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "System" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "System-Docker ist auch verfügbar" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Etikett" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Etiketten" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Die Cockpit Benutzeroberfläche für Docker Container." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "" + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Die maximal zulässige Zeit für den Abschluss der Gesundheitsprüfung, bevor " +"ein Intervall als fehlgeschlagen gilt." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Die Anzahl der zulässigen Wiederholungsversuche, bevor eine " +"Gesundheitsprüfung als ungesund gilt." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Zeitüberschreitung" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Fehler suchen" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Tippen zum filtern…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Abbildverlauf kann nicht geladen werden" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Ungesund" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Läuft seit $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Veraltetes Docker-Format verwenden" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Benutzt von" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Benutzer" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Benutzer Docker ist auch verfügbar" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Benutzer:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Wert" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Datenträger" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Wenn ungesund" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Mit Terminal" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Beschreibbar" + +#: src/manifest.json:0 +msgid "container" +msgstr "container" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "wird heruntergeladen" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "Host[:Port]/[Benutzer]/Container[:Tag]" + +#: src/manifest.json:0 +msgid "image" +msgstr "Image" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "in" + +#: src/ImageDeleteModal.jsx:79 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate" +msgstr "Intermediate Images verstecken" + +#: src/ImageDeleteModal.jsx:59 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate image" +msgstr "Intermediate Images verstecken" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "n.v." + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "nicht verfügbar" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "Pod-Gruppe" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "Ports" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "Sekunden" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "System" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "ungenutzt" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "Benutzer:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "Volumen" + +#~ msgid "Delete $0" +#~ msgstr "$0 löschen" + +#~ msgid "select all" +#~ msgstr "Alles auswählen" + +#~ msgid "Restarting" +#~ msgstr "Wird neu gestartet" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Löschen von $0 bestätigen" + +#, fuzzy +#~| msgid "Please confirm deletion of pod $0" +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Löschen von Pod $0 bestätigen" + +#, fuzzy +#~| msgid "Please confirm force deletion of pod $0" +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Erzwungenes Löschen von Pod $0 bestätigen" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Erzwungenes Löschen von $0 bestätigen" + +#~ msgid "Container is currently running." +#~ msgstr "Container läuft gerade." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Keine root-Dateisystem-Änderungen beifügen, wenn exportieren" + +#~ msgid "Start after creation" +#~ msgstr "Nach der Erstellung starten" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Nicht verwendete $0 Abbilder löschen:" + +#~ msgid "created" +#~ msgstr "erstellt" + +#~ msgid "exited" +#~ msgstr "beendet" + +#~ msgid "paused" +#~ msgstr "pausiert" + +#~ msgid "running" +#~ msgstr "Läuft" + +#~ msgid "stopped" +#~ msgstr "Angehalten" + +#~ msgid "user" +#~ msgstr "Benutzer" + +#~ msgid "Add on build variable" +#~ msgstr "Build-Variable hinzufügen" + +#~ msgid "Commit image" +#~ msgstr "Image committen" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Message" +#~ msgstr "Nachricht" + +#~ msgid "Pause the container" +#~ msgstr "Den Container anhalten" + +#~ msgid "Remove on build variable" +#~ msgstr "Bei Bau-Variable entfernen" + +#~ msgid "Add item" +#~ msgstr "Element hinzufügen" + +#, fuzzy +#~| msgid "Host port" +#~ msgid "Host port (optional)" +#~ msgstr "Host-Port" + +#~ msgid "ReadOnly" +#~ msgstr "Nur lesen" + +#~ msgid "IP prefix length" +#~ msgstr "IP-Präfixlänge" + +#~ msgid "Get new image" +#~ msgstr "Neues Image herunterladen" + +#~ msgid "Run" +#~ msgstr "Starten" + +#~ msgid "On build" +#~ msgstr "Beim Bauen" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Sind Sie sicher, dass Sie dieses Image löschen wollen?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Konnte nicht mit diesem Container verbinden: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Konnte keinen Kanal öffnen: $0" + +#~ msgid "Everything" +#~ msgstr "Alles" + +#~ msgid "Security" +#~ msgstr "Sicherheit" + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "Diese Version der Web-Konsole unterstützt kein Terminal." diff --git a/ui/cockpit-docker/po/es.po b/ui/cockpit-docker/po/es.po new file mode 100644 index 0000000..61212d3 --- /dev/null +++ b/ui/cockpit-docker/po/es.po @@ -0,0 +1,1489 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Álvaro Castillo , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-12-15 14:41+0000\n" +"Last-Translator: Neftali Yagua \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 5.3\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 contenedor" +msgstr[1] "$0 contenedores" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 imagen, $1" +msgstr[1] "$0 imágenes en total, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 segundo" +msgstr[1] "$0 segundos" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 imagen sin usar, $1" +msgstr[1] "$0 imágenes sin usar, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 a 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" +"Acción a tomar una vez que el contenedor pase a un mal estado de salud." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Añadir mapeo de puertos" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Añadir variable" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Añadir volumen" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Todos" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Todos los registros" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Siempre" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Ocurrió un error" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Autor" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Iniciar docker en el arranque" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Ayuda sobre shares de CPU" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Shares de CPU" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"Los shares de CPU determinan la prioridad de ejecución de contenedores. La " +"prioridad por defecto es 1024. Un número mayor prioriza este contenedor. Un " +"número menor reduce la prioridad." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Cancelar" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Comprobando estado de salud" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Checkpoint" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Soporte para checkpoint y restauración" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Crear checkpoint del contenedor $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Pulse para ver los puertos publicados" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Pulse para ver los volúmenes" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Componente Cockpit para contenedores Docker" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Comando" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Comentarios" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Commit" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Confirmar contenedor" + +#: src/util.js:23 +msgid "Configured" +msgstr "Configurado" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Consola" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Contenedores" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Falló al crear el contenedor" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "El contenedor no pudo ser iniciado" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "El contenedor no se está ejecutando" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Nombre de contenedor" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Se requiere un nombre para el contenedor." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Ruta del contenedor" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "La ruta del contenedor no debe estar vacía" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Puerto del contenedor" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "El puerto de contenedores no debe estar vacío" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Contenedores" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Crear" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Crear una imagen nueva basada en el estado actual del contenedor $0." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Crear y ejecutar" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Crear contenedor" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Crear contenedor en $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Crear un contenedor en el pod" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Crear pod" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Creado" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Creada por" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Reducir shares de CPU" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Reducir intervalo" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Reducir el número máximo de reintentos" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Reducir la cantidad de memoria" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Reducir el número de reintentos" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Reducir el periodo de arranque" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Reducir el tiempo de espera" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Eliminar" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "¿Eliminar imagen de $0?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "¿Eliminar $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Eliminar Imagen" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "¿Eliminar pod $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Borrar imágenes seleccionadas" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Borrar imágenes del sistema sin usar:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Borrar imágenes del usuario sin usar:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Eliminando un contenedor se borrará toda la información que hay en él." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "" +"Eliminando un contenedor en ejecución borrará toda la información que haya " +"en él." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Eliminando este pod eliminará los siguientes contenedores:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Detalles" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Tamaño en disco" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"El formato Docker es útil para compartir la imagen con Docker o Moby Engine" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Descargar" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Descargar nueva imagen" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "El pod $0, vacío, será eliminado permanentemente." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Punto de entrada" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Variables de entorno" + +#: src/util.js:26 +msgid "Error" +msgstr "Error" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Mensaje de error" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Hubo un error al conectar la consola" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Por ejemplo, Tu Nombre " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Por ejemplo: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Finalizado" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Comprobación de estado de salud fallada" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Fallo hacer el checkpoint del contenedor $0" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Fallo al limpiar el contenedor" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Falló hacer el commit en el contenedor $0" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Fallo al crear el contenedor $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Fallo al descargar la imagen $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Falló al forzar el borrado del contenedor $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Fallo al forzar el borrado de la imagen $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Fallo al reiniciar forzadamente el pod $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Fallo al detener forzadamente el pod $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Fallo al pausar el contenedor $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Fallo al pausar el pod $0" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Fallo al eliminar los contenedores no utilizados" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Fallo al eliminar las imágenes no usadas" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Fallo al obtener la imagen $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Falló al eliminar el contenedor $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Fallo al eliminar la imagen $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Fallo al renombrar el contenedor $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Falló al reiniciar el contenedor $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Fallo al reiniciar el pod $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Fallo al restaurar el contenedor $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Fallo al reanudar el contenedor $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Fallo al reanudar el pod $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Fallo al iniciar el contenedor $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Fallo al comprobar el estado de salud del contenedor $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Fallo al buscar imágenes." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Fallo al buscar las imágenes: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Falló al buscar nuevas imágenes" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Falló al iniciar el contenedor $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Fallo al iniciar el pod $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Falló al parar el contenedor $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Fallo al parar el pod $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Racha de fallos" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Forzar commit" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Forzar el borrado" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "¿Forzar la eliminación del pod $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Forzar el reinicio" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Forzar la parada" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Puerta de enlace" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Comprobación del estado de salud" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Ayuda sobre el intervalo de comprobación del estado de salud" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "" +"Ayuda sobre el número de reintentos de comprobación del estado de salud" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Ayuda sobre el periodo de arranque de comprobación del estado de salud" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Ayuda sobre el tiempo de espera de comprobación del estado de salud" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Ayuda sobre la acción al fallo al comprobar el estado de salud" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Buen estado de salud" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Ocultar imágenes" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Ocultar imágenes intermedias" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historial" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Ruta del anfitrión" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Puerto del anfitrión" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Ayuda sobre el puerto del anfitrión" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "Dirección IP" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Ayuda sobre la dirección IP" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Idóneo para entornos de desarrollo" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Idóneo para ejecutar servicios" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Si la IP del host se asigna a 0.0.0.0 o no se asigna, el puerto se asociará " +"a todas las IP's del host." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Si no se asigna el puerto del host, el puerto del contenedor se asignará a " +"un puerto aleatorio del host." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ignorar la dirección IP si se ha configurado de forma estática" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ignorar la dirección MAC si se ha configurado de forma estática" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Imagen" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "El nombre de la imagen no es único" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Se requiere un nombre para la imagen" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Ayuda sobre la selección de imagen" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Imágenes" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Incrementar shares de CPU" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Incrementar el intervalo" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Incrementar el número máximo de reintentos" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Incrementar la cantidad de memoria" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Incrementar el número de reintentos" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Incrementar el periodo de arranque" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Incrementar el tiempo de espera" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integración" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Intervalo" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Cada cuánto se ejecuta la comprobación del estado de salud." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Carácteres inválidos. El nombre sólo puede contener letras, números y " +"ciertos signos de puntuación (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Mantener todos los archivos temporales de checkpoint" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Clave" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "La clave no debe estar vacía" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Últimas 5 comprobaciones" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Último checkpoint" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Seguir ejecutando tras escribir el checkpoint en disco" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Cargando detalles..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Cargando registros..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Cargando..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Local" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Imágenes locales" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Registros" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "Dirección MAC" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Número máximo de reintentos" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Memoria" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Límite de memoria" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Unidad de medida de memoria" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Modo" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Existen múltiples etiquetas para esta imagen. Seleccione las imágenes " +"etiquetadas a eliminar." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "Debe ser una dirección IP válida" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Nombre" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Nombre ya en uso" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Nuevo nombre del contenedor" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Nombre de la nueva imagen" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "No" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Ninguna acción" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "No hay contenedores" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "No hay contenedores que utilicen esta imagen" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "No hay contenedores en este pod" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "No hay contenedores relacionados con los criterios de búsqueda" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "No se han especificado variables de entorno" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "No hay imágenes" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "No se han encontrado imágenes" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "No hay imágenes relacionadas con el criterio de búsqueda" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Sin etiqueta" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "No hay puertos expuestos" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "No hay resultados para $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "No hay contenedores ejecutándose" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "No se han especificado volúmenes" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "En caso de fallo" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Sólo los que se están ejecutando" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Opciones" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Propietario" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Ayuda sobre el propietario" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Comprobación de estado de salud superada" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Pegue una o más líneas de pares clave=valor en cualquier campo para importar " +"en masa" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Pausar" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Pausar el contenedor cuando se cree la imagen" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Pausado" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Fallo al crear el pod" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Nombre del pod" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Contenedores de Docker" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "El servicio Docker no está activo" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Mapeo de puertos" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Puertos" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Se pueden mapear puertos inferiores a 1024" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Privado" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protocolo" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Eliminar" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Eliminar contenedores no utilizados" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Eliminar imágenes no utilizadas" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Eliminando contenedores" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Eliminando imágenes no utilizadas" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Obtener la última imagen" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Obteniendo" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Acceso de sólo lectura" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Acceso de lectura y escritura" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Eliminar elemento" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Elimina los contenedores seleccionados que no se están ejecutando" + +#: src/util.js:23 +msgid "Removing" +msgstr "Eliminándose" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Renombrar" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Renombrar el contenedor $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Se pueden establecer límites sobre los recursos" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Reiniciar" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Política de reinicio" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Ayuda sobre la política de reinicio" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Política de reinicio a seguir cuando se cierren contenedores." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Política de reinicio a seguir cuando los contenedores finalicen. Utilizar " +"linger para iniciar contenedores automáticamente puede no funcionar bajo " +"ciertas circunstancias, como cuando se emplean ecryptfs, systemd-homed, NFS " +"o 2FA en una cuenta de usuario." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Restaurar" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Restaurar el contenedor $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Restaurar con las conexiones TCP establecidas" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Restringido por los permisos de la cuenta de usuario" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Reanudar" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Número de reintentos" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Pruebe con otro término." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Ejecutar comprobación de estado de salud" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Ejecutándose" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Buscar por nombre o descripción" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Buscar por registro" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Buscar" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Buscar una imagen" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Buscar cadena o ubicación de contenedor" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Buscando…" + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Buscando: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Compartido" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Mostrar" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Mostrar imágenes" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Mostrar imágenes intermedias" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Mostrar menos" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Mostrar más" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Tamaño" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Iniciar" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Periodo de arranque" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Iniciar docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Comience a escribir para buscar imágenes." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Comenzó" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Estado" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Estado" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Parar" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Detenido" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Habilitar la preservación de las conexiones TCP establecidas" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Sistema" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "El servicio de sistema Docker también está disponible" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Etiqueta" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Etiquetas" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "La interfaz de usuario de Cockpit para contenedores Docker." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "El tiempo de inicialización necesario para que un contenedor arranque." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"El máximo tiempo permitido para completar una comprobación de estado de " +"salud antes de que se considere fallada." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"El máximo número de reintentos permitidos antes de que se considere un mal " +"estado de salud." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Tiempo de espera" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Solución de errores" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Escriba para establecer un criterio de búsqueda…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "No se pudo cargar el historial de imágenes" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Mal estado de salud" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Levantado desde $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Usar el formato heredado Docker" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Usado por" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Usuario" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "El servicio de usuario Docker también está disponible" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Usuario:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Valor" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Volúmenes" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "En caso de mal estado de salud" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Con terminal" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Puede escribirse" + +#: src/manifest.json:0 +msgid "container" +msgstr "contenedor" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "descargando" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:puerto]/[usuario]/contenedor[:etiqueta]" + +#: src/manifest.json:0 +msgid "image" +msgstr "imagen" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "en" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "intermedia" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "imagen intermedia" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "sin/aplicar" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "no disponible" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "Grupo de pod" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "puertos" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "segundos" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "sistema" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "sin utilizar" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "usuario:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "volúmenes" + +#~ msgid "Delete $0" +#~ msgstr "Eliminar $0" + +#~ msgid "select all" +#~ msgstr "seleccionar todas" + +#~ msgid "Failure action" +#~ msgstr "Acción al fallo" + +#~ msgid "Restarting" +#~ msgstr "Reiniciándose" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Confirme el borrado de $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Confirme el borrado del pod $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Confirme el borrado forzado del pod $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Confirme forzar el borrado de $0" + +#~ msgid "Container is currently running." +#~ msgstr "El contenedor se está ejecutando." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "No incluir cambios en el sistema de archivos raíz al exportar" + +#, fuzzy +#~| msgid "Get new image" +#~ msgid "Delete unused $0 images:" +#~ msgstr "Obtener nueva imagen" + +#, fuzzy +#~| msgid "Created" +#~ msgid "created" +#~ msgstr "Creado" + +#, fuzzy +#~| msgid "Exited" +#~ msgid "exited" +#~ msgstr "Cerrado" + +#, fuzzy +#~| msgid "Pause" +#~ msgid "paused" +#~ msgstr "Pausar" + +#, fuzzy +#~| msgid "user" +#~ msgid "user" +#~ msgstr "usuario" + +#, fuzzy +#~| msgid "Set container on build variables" +#~ msgid "Add on build variable" +#~ msgstr "Establecer el contenedor en las variables de construcción" + +#~ msgid "Commit image" +#~ msgstr "Commit una imagen" + +#~ msgid "Format" +#~ msgstr "Formato" + +#~ msgid "Message" +#~ msgstr "Mensaje" + +#~ msgid "Pause the container" +#~ msgstr "Pausar el contenedor" + +#, fuzzy +#~| msgid "Set container on build variables" +#~ msgid "Remove on build variable" +#~ msgstr "Establecer el contenedor en las variables de construcción" + +#~ msgid "Set container on build variables" +#~ msgstr "Establecer el contenedor en las variables de construcción" + +#, fuzzy +#~| msgid "Host port" +#~ msgid "Host port (optional)" +#~ msgstr "Puerto del anfitrión" + +#~ msgid "ReadOnly" +#~ msgstr "SoloLectura" + +#~ msgid "Run" +#~ msgstr "Ejecutar" + +#~ msgid "On build" +#~ msgstr "En construcción" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "¿Está seguro de que quiere eliminar esta imagen?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "No se pudo asociar a este contenedor: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "No se pudo abrir un canal: $0" + +#~ msgid "Everything" +#~ msgstr "Todo" + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "Esta versión de consola Web no soporta un terminal." diff --git a/ui/cockpit-docker/po/fi.po b/ui/cockpit-docker/po/fi.po new file mode 100644 index 0000000..996b600 --- /dev/null +++ b/ui/cockpit-docker/po/fi.po @@ -0,0 +1,1484 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2024-02-20 20:36+0000\n" +"Last-Translator: Jan Kuparinen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 5.4\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 kontti" +msgstr[1] "$0 konttia" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 levykuva yhteensä, $1" +msgstr[1] "$0 levykuvaa yhteensä, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 sekunti" +msgstr[1] "$0 sekuntia" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 käyttämätön levykuva, $1" +msgstr[1] "$0 käyttämätöntä levykuvaa, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "Toimenpiteet, kun kontti siirtyy epäterveelliseen tilaan." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Lisää porttiassosiaatio" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Lisää muuttuja" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Lisää taltio" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Kaikki" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Kaikki rekisterit" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Aina" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Tapahtui virhe" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Tekijä" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Käynnistä docker automaattisesti käynnistyksen yhteydessä" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "Suoritin" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Ohjeita CPU-osuuksista" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Suoritinosuus" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU-osuudet määrittävät käynnissä olevien konttien prioriteetin. " +"Oletusprioriteetti on 1024. Suurempi numero priorisoi tätä konttia. Pienempi " +"numero laskee prioriteettia." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Peru" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Tarkistetaan tilaa" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Tarkistuspiste" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Tarkistuspisteen ja palautuksen tuki" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Luo tarkistuspiste kontista $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Napsauta nähdäksesi julkaistut portit" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Napsauta nähdäksesi taltiot" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Cockpit-komponentti Docker-konteille" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Komento" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Kommentit" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Kommitoi" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Kommitoi kontti" + +#: src/util.js:23 +msgid "Configured" +msgstr "Asetukset asetettu" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konsoli" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Kontti" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Kontin luonti epäonnistui" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Kontin käynnistys epäonnistui" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Kontti ei ole käynnissä" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Kontin nimi" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Kontin nimi vaaditaan." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Kontin polku" + +#: src/Volume.jsx:23 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container path must not be empty" +msgstr "Kontin luonti epäonnistui" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Kontin portti" + +#: src/PublishPort.jsx:37 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container port must not be empty" +msgstr "Kontin luonti epäonnistui" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Kontit" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Luo" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Luo uusi levykuva $0-kontin nykyisen tilan perusteella." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Luo ja suorita" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Luo kontti" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Luo kontti kohteeseen $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Luo kontti podiin" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Luo podi" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Luotu" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Tekijä" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Vähennä suoritinosuuksia" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Pienennä väliä" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Pienennä uudelleenyritysten enimmäismäärää" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Vähennä muistia" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Vähennä uudelleenyrityksiä" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Pienennä aloitusaikaa" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Pienennä aikakatkaisua" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Poista" + +#: src/ImageDeleteModal.jsx:92 +#, fuzzy +#| msgid "Delete $0?" +msgid "Delete $0 image?" +msgstr "Poista $0?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Poista $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Poista levykuva" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Poista podi $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Poista merkityt kuvat" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Poista käyttämättömät järjestelmälevykuvat:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Poista käyttämättömät käyttäjän levykuvat:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Kontin poistaminen tuhoaa kaiken sillä olevan datan." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "Käynnissä olevan kontin poistaminen tuhoaa kaiken sillä olevan datan." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Tämän podin poisto poistaa seuraavat kontit:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Yksityiskohdat" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Levytila" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Docker-muoto on hyödyllinen, kun levykuvaa jaetaan Dockerin tai Moby Enginen " +"kanssa" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Lataa" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Lataa uusi levykuva" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Tyhjä podi $0 poistetaan pysyvästi." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Sisääntulokohta" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Ympäristömuuttujat" + +#: src/util.js:26 +msgid "Error" +msgstr "Virhe" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Virheviesti" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Virhe konsolia liitettäessä" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Esimerkki: Nimesi " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Esimerkki: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Päättyi" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Epäonnistunut eheysajo" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Kontin $0 tarkistuspisteen luominen epäonnistui" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Kontin poistaminen epäonnistui" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Kontin $0 kommitointi epäonnistui" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Kontin $0 luominen epäonnistui" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Levykuvan lataaminen epäonnistui $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Kontin $0 pakotettu poistaminen epäonnistui" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Levykuvan $0 pakotettu poistaminen epäonnistui" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Podin $0 pakotettu uudelleenkäynnistäminen epäonnistui" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Podin $0 pakotettu pysäyttäminen epäonnistui" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Kontin $0 keskeyttäminen epäonnistui" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Podin $0 keskeyttäminen epäonnistui" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Käyttämättömien konttien poisto epäonnistui" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Käyttämättömien levykuvien karsiminen epäonnistui" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Levykuvan $0 hakeminen epäonnistui" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Kontin $0 poistaminen epäonnistui" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Levykuvan $0 poistaminen epäonnistui" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Kontin $0 uudelleennimeäminen epäonnistui" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Kontin $0 uudelleenkäynnistäminen epäonnistui" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Podin $0 uudelleenkäynnistäminen epäonnistui" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Kontin $0 palauttaminen epäonnistui" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Kontin $0 palauttaminen epäonnistui" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Podin $0 käytön jatkaminen epäonnistui" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Kontin $0 suorittaminen epäonnistui" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Kontin $0 eheystarkastus epäonnistui" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Levykuvien etsintä epäonnistui." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Levykuvien etsintä epäonnistui: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Uusien levykuvien etsintä epäonnistui" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Kontin $0 käynnistäminen epäonnistui" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Podin $0 käynnistäminen epäonnistui" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Kontin $0 pysäyttäminen epäonnistui" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Podin $0 pysäyttäminen epäonnistui" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Epäonnistunut sarja" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Pakota kommitti" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Pakota poisto" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Pakota podin $0 poisto?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Pakota uudelleenkäynnistys" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Pakota pysäytys" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "Gt" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Yhdyskäytävä" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Eheystarkistus" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Tietoa eheystarkistuksen aikavälistä" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Tietoa eheystarkistuksen uudelleenyrityksistä" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Tietoa eheystarkistuksen aloitusjaksosta" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Tietoa eheystarkistuksen aikakatkaisusta" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Tietoa terveystarkistuksen virhetilan toimenpiteistä" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Ehjä" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Piilota levykuvat" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Piilota välivaiheen levykuvat" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historia" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Koneen polku" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Koneen portti" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Ohjeita koneen portista" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "TUNNISTE" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP-osoite" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Ohjeita IP-osoitteesta" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Ihanteellinen kehittämiseen" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Ihanteellinen palvelujen suorittamiseen" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Jos isäntäkoneen IP-osoitteeksi on asetettu 0.0.0.0 tai sitä ei ole " +"määritetty lainkaan, portti sidotaan kaikkiin isäntäkoneen IP-osoitteisiin." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Jos isäntäporttia ei ole asetettu, konttiportille määritetään satunnainen " +"isäntäportti." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ohita IP-osoite, jos se on asetettu staattisesti" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ohita MAC-osoite, jos se on asetettu staattisesti" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Levykuva" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Kevykuvan nimi ei ole ainutlaatuinen" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Levykuvan nimi vaaditaan" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Ohjeita levykuvan valintaan" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Levykuvat" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Lisää suoritinosuuksia" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Suurenna väliä" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Lisää uudelleenyritysten enimmäismäärää" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Lisää muistia" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Lisää uudelleenyrityksiä" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Pidennä aloitusjaksoa" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Nosta aikakatkaisua" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integraatio" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Aikaväli" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Eheystarkistusten aikaväli." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Virheellisiä merkkejä. Nimi voi sisältää vain kirjaimia, numeroita ja " +"tiettyjä välimerkkejä (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "Kt" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Säilytä kaikki väliaikaiset tarkistuspistetiedostot" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Avain" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "Avain ei saa olla tyhjä" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Viimeiset 5 ajoa" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Viimeisin tarkistuspiste" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Jätä käyntiin tarkistuspisteen levylle kirjoittamisen jälkeen" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Ladataan tietoja..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Ladataan lokeja..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Ladataan..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Paikallinen" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Paikallisia levykuvia" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Lokit" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC-osoite" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "Mt" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Uudelleenyritysten enimmäismäärä" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Muisti" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Muistiraja" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Muistiyksikkö" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Tila" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Tälle levykuvalle on useita tunnisteita. Valitse tunnisteelliset levykuvat " +"jotka poistetaan." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Nimi" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Nimi on jo käytössä" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Kontin uusi nimi" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Uusi levykuvan nimi" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Ei" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Ei toimintoa" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Ei kontteja" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Yksikään kontti ei käytä tätä levykuvaa" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Tässä podissa ei ole kontteja" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Ei nykyistä suodatusta vastaavia kontteja" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Ympäristömuuttujia ei ole määritetty" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Ei levykuvia" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Levykuvia ei löytynyt" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Ei nykyistä suodatusta vastaavia levykuvia" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Ei nimiötä" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Ei paljastettuja portteja" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Ei tuloksia hakusanalle $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Ei käynnissä olevia kontteja" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Taltiota ei ole määritelty" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Epäonnistumisesta" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Vain käynnissä olevat" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Valinnat" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "omistaja" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Omistajan ohjeet" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Onnistunut eheysajo" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Liitä yksi tai useampi rivi avain=arvo-pareja mihin tahansa kenttään " +"joukkotuontia varten" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Keskeytä" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Pysäytä kontti levykuvan luomisen ajaksi" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Keskeytetty" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Podin luonti epäonnistui" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Podin nimi" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker-kontit" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker-palvelu ei ole aktiivinen" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Porttiassosiaatio" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Portit" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Portit alle 1024 voidaan kartoittaa" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Yksityinen" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokolla" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Karsi" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Poista käyttämättömiä kontteja" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Karsi käyttämättömät levykuvat" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Siivotaan kontteja" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Karsitaan levykuvia" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Hae viimeisin levykuva" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Haetaan" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Vain luku-käyttöoikeus" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Luku-kirjoitusoikeus" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Poista kohde" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Poistaa valitut ei käynnissä olevat kontit" + +#: src/util.js:23 +msgid "Removing" +msgstr "Poistetaan" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Nimeä uudelleen" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Nimeä kontti $0 uudelleen" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Resurssirajoja voidaan asettaa" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Käynnistä uudelleen" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Uudelleenkäynnistyksen käytäntö" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Ohjeita uudelleenkäynnistyksen käytännöstä" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Noudata uudelleenkäynnistyskäytäntöä, kun kontit poistuvat." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Käytettävä uudelleenkäynnistyskäytäntö, kun kontit poistuvat. Viivyttämisen " +"käyttäminen konttien automaattiseen käynnistykseen ei välttämättä toimi " +"joissain olosuhteissa, kuten kun käyttäjätilillä on käytössä ecryptfs, " +"systemd-homed, NFS tai 2FA." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Palauta" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Palauta kontti $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Palauta käyttäen luotuja TCP-yhteyksiä" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Rajoitettu käyttäjätilin käyttöoikeuksilla" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Jatka" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Uudelleenyritykset" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Yritä toisella termillä uudelleen." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Aja eheystarkistus" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Käynnissä" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Hae nimen tai kuvauksen perusteella" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Haku rekisterin perusteella" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Etsittävä" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Etsi levykuvaa" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Hae merkkijonon tai kontin sijaintia" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Etsitään..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Etsitään: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Jaettu" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Näytä" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Näytä levykuvat" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Näytä välivaiheen levykuvat" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Näytä vähemmän" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Näytä lisää" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Koko" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Käynnistä" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Aloitusjakso" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Käynnistä docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Aloita kirjoittaminen etsiäksesi levykuvia." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Käynnistetty klo" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Tila" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Tila" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Pysäytä" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Pysäytetty" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Tue jo luotujen TCP -yhteyksien säilyttämistä" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Järjestelmä" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Järjestelmän Docker-palvelu on myös saatavilla" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Tunniste" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Tunnisteet" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Cockpit-käyttöliittymä Docker-konteille." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Alustusaika, joka tarvitaan kontin käynnistymiseen." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Enimmäisaika, joka on sallittu eheystarkastuksen suorittamiseen ennen kuin " +"se katsotaan epäonnistuneeksi." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Yritysten enimmäismäärä, joka on sallittu eheystarkastuksen suorittamiseen " +"ennen kuin se katsotaan epäonnistuneeksi." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Aikakatkaisu" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Vianetsintä" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Kirjoita suodattaaksesi…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Levykuvan historian lataaminen epäonnistui" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Rikki" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Käynnissä $0 lähtien" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Käytä vanhaa Docker-muotoa" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Käyttää" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Käyttäjä" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Käyttäjän Docker-palvelu on myös saatavilla" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Käyttäjä:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Arvo" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Taltiot" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Kun rikki" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Päätteen kanssa" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Kirjoitettavissa" + +#: src/manifest.json:0 +msgid "container" +msgstr "kontti" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "ladataan" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:port]/[user]/container[:tag]" + +#: src/manifest.json:0 +msgid "image" +msgstr "levykuva" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "sijainnissa" + +#: src/ImageDeleteModal.jsx:79 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate" +msgstr "Piilota välivaiheen levykuvat" + +#: src/ImageDeleteModal.jsx:59 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate image" +msgstr "Piilota välivaiheen levykuvat" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "ei sovellu" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "ei käytettävissä" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "podiryhmä" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "portit" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "sekuntia" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "järjestelmä" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "ei käytössä" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "käyttäjä:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "taltiot" + +#~ msgid "Delete $0" +#~ msgstr "Poista $0" + +#~ msgid "select all" +#~ msgstr "valitse kaikki" + +#~ msgid "Failure action" +#~ msgstr "virhetilan toimenpiteet" + +#~ msgid "Restarting" +#~ msgstr "Käynnistyy uudelleen" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Vahvista kohteen $0 poistaminen" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Vahvista podin $0 poistaminen" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Vahvista podin $0 pakotettu poistaminen" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Vahvista kohteen $0 pakotettu poistaminen" + +#~ msgid "Container is currently running." +#~ msgstr "Kontti on parhaillaan käynnissä." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Älä sisällytä juuritiedostojärjestelmän muutoksia vientiä varten" + +#~ msgid "Default with single selectable" +#~ msgstr "Oletusarvo kun yksi valittavissa" + +#~ msgid "Start after creation" +#~ msgstr "Käynnistä luomisen jälkeen" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Poista käyttämättömät $0 levykuvat:" + +#~ msgid "created" +#~ msgstr "luotu" + +#~ msgid "exited" +#~ msgstr "päättyi" + +#~ msgid "paused" +#~ msgstr "pysäytetty" + +#~ msgid "running" +#~ msgstr "suoritetaan" + +#~ msgid "stopped" +#~ msgstr "pysäytetty" + +#~ msgid "user" +#~ msgstr "käyttäjä" + +#~ msgid "Add on build variable" +#~ msgstr "Lisää koontimuuttuja" + +#~ msgid "Commit image" +#~ msgstr "Commit-levykuva" + +#~ msgid "Format" +#~ msgstr "Alusta" + +#~ msgid "Message" +#~ msgstr "Viesti" + +#~ msgid "Pause the container" +#~ msgstr "Keskeytä kontin ajo" + +#~ msgid "Remove on build variable" +#~ msgstr "Poista koontimuuttujalla" + +#~ msgid "Set container on build variables" +#~ msgstr "Aseta kontti koontimuuttujiin" + +#~ msgid "Add item" +#~ msgstr "Lisää kohta" + +#~ msgid "Host port (optional)" +#~ msgstr "Koneen portti (valinnainen)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (valinnainen)" + +#~ msgid "ReadOnly" +#~ msgstr "Vain-luku" + +#~ msgid "IP prefix length" +#~ msgstr "IP Prefix Pituus" + +#~ msgid "Run" +#~ msgstr "Suorita" diff --git a/ui/cockpit-docker/po/fr.po b/ui/cockpit-docker/po/fr.po new file mode 100644 index 0000000..cce1d6e --- /dev/null +++ b/ui/cockpit-docker/po/fr.po @@ -0,0 +1,1529 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Julien Humbert , 2020. +# Timothée Ravier , 2020. +# Sébastien Pascal-Poher , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-05-30 13:20+0000\n" +"Last-Translator: Ludek Janda \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1\n" +"X-Generator: Weblate 4.17\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 conteneur" +msgstr[1] "$0 conteneurs" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 image total, $1" +msgstr[1] "$0 images total, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 seconde" +msgstr[1] "$0 secondes" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 image non utilisée, $1" +msgstr[1] "$0 images non utilisées, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "Action à entreprendre lorsque le conteneur passe à un état insalubre." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Ajouter un mappage de port" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Ajouter une variable" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Ajouter volume" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Tous" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Tous les registres" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Toujours" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Une erreur s’est produite" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Auteur" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Démarrer automatiquement docker au démarrage" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Assistance CPU Shares" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Parts de CPU" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU Shares déterminent la priorité des conteneurs en cours d'exécution. La " +"priorité par défaut est de 1024. Un nombre plus élevé donne la priorité à ce " +"conteneur. Un nombre inférieur diminue la priorité." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Annuler" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Contrôle de fonctionnement" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Point de contrôle" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Prise en charge des points de contrôle et des restaurations" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Point de contrôle du conteneur $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Cliquez pour voir les ports publiés" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Cliquez pour voir les volumes" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Composant Cockpit pour les conteneurs Docker" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Commande" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Commentaires" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Valider" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Valider conteneur" + +#: src/util.js:23 +msgid "Configured" +msgstr "Configuré" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Console" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Conteneur" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Le conteneur n’a pas pu être créé" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Le conteneur n’a pas pu être démarré" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Le conteneur n’est pas en cours d’exécution" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Nom du conteneur" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Le nom du conteneur est obligatoire." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Chemin du conteneur" + +#: src/Volume.jsx:23 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container path must not be empty" +msgstr "Le conteneur n’a pas pu être créé" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Port du conteneur" + +#: src/PublishPort.jsx:37 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container port must not be empty" +msgstr "Le conteneur n’a pas pu être créé" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Conteneurs" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Créer" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Créer une nouvelle image basée sur l'état actuel du conteneur $0." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Créer et démarrer" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Créer un conteneur" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Créer un conteneur dans $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Créer un conteneur dans un pod" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Créer un pod" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Créé" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Créé par" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Diminution des parts de CPU" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Diminution de l'intervalle" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Diminuer le nombre maximum de tentatives" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Diminution de la mémoire" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Diminuer les tentatives" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Diminution de la période de démarrage" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Diminuer le délai d'attente" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Supprimer" + +#: src/ImageDeleteModal.jsx:92 +#, fuzzy +#| msgid "Delete $0?" +msgid "Delete $0 image?" +msgstr "Supprimer $0 ?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Supprimer $0 ?" + +#: src/ImageDeleteModal.jsx:96 +#, fuzzy +#| msgid "Delete tagged images" +msgid "Delete image" +msgstr "Supprimer les images taguées" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Supprimer le pod $0 ?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Supprimer les images taguées" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Supprimer les images système non utilisées :" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Supprimer les images utilisateur non utilisées :" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Supprimer un conteneur va effacer toutes les données qu’il contient." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "" +"La suppression d'un conteneur en cours d'exécution efface toutes les données " +"qu'il contient." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "La suppression de ce pod entraînera celle des conteneurs suivants :" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Détails" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Espace disque" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Le format Docker est utile pour partager l'image avec Docker ou Moby Engine" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Télécharger" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Télécharger la nouvelle image" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Le pod vide $0 sera définitivement supprimé." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Point d’entrée" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Variables d’environnement" + +#: src/util.js:26 +msgid "Error" +msgstr "Erreur" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Message d’erreur" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Une erreur s’est produite lors de la connexion à la console" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Exemple, votre nom " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Exemple : $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Quittés" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Échec de l’exécution du bilan de fonctionnement" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Échec de la création du point de contrôle du conteneur $0" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Échec du nettoyage du conteneur" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Échec de la validation du conteneur $0" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Échec de la création du conteneur $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Échec du téléchargement de l’image $0 : $1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Échec de la suppression forcée du conteneur $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Échec de la suppression forcée de l’image $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Échec du redémarrage forcé du pod $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Échec de l'arrêt forcé du pod $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Échec de la mise en pause du conteneur $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Échec de la mise en pause du pod $0" + +#: src/PruneUnusedContainersModal.jsx:57 +#, fuzzy +#| msgid "Failed to prune unused images" +msgid "Failed to prune unused containers" +msgstr "Échec de la suppression des images non utilisées" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Échec de la suppression des images non utilisées" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Échec d’extraction de l’image $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Échec de la suppression du conteneur $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Échec de la suppression de l’image $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Échec du renommage du conteneur $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Échec du redémarrage du conteneur $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Échec du redémarrage du pod $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Échec de la restauration du conteneur $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Échec de la reprise conteneur $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Échec de la reprise pod $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Échec du démarrage du conteneur $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Échec de l'exécution du contrôle de fonctionnement du conteneur $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Échec de la recherche d'images." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Échec de la recherche de l'image : $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Échec de la recherche de nouvelles images" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Échec du démarrage du conteneur $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Échec du démarrage du pod $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Échec de l’arrêt du conteneur $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Échec de l’arrêt du pod $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Une série d'échecs" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Validation forcée" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Suppression forcée" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Forcer la suppression du pod $0 ?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Redémarrage forcé" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Arrêt forcé" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "Go" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Passerelle" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Bilan de fonctionnement" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Aide à l'intervalle entre les bilans de fonctionnement" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Aide pour les tentatives de bilans de fonctionnement" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Aide pour la période de démarrage du bilan de fonctionnement" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Aide sur le délai d'exécution du bilan de fonctionnement" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Aide à l’action pour les bilans de fonctionnement" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Fonctions intactes" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Cacher les images" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Cacher les images intermédiaires" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historique" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Chemin vers l’hôte" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Port de l’hôte" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Assistance Port d’hôte" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "Adresse IP" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Assistance Adresse IP" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Idéal pour le développement" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Idéal pour le fonctionnement des services" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Si l’IP de l’hôte est définie ainsi 0.0.0.0 ou si elle n’est pas dutout " +"définie, le port sera relié à tous les IP de l’hôte." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Si le port de l’hôte n’est pas défini, le port du conteneur sera assigné au " +"hasard sur l’hôte." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ignorer l'adresse IP si définie statiquement" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ignorer l'adresse MAC si définie statiquement" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Image" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Le nom de l'image n'est pas unique" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Le nom de l'image est obligatoire" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Aide à la sélection d'images" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Images" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Augmenter les parts de CPU" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Augmenter l'intervalle" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Augmenter le nombre maximum de tentatives" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Augmenter la mémoire" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Augmenter les tentatives" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Augmenter la période de démarrage" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Augmenter le délai d'attente" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Intégration" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Intervalle" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Intervalle à partir duquel le contrôle de fonctionnement est exécuté." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Caractères non valides. Le nom ne peut contenir que des lettres, des " +"chiffres et certains signes de ponctuation (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "Ko" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Conserver tous les fichiers de points de contrôle temporaires" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Clé" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Les 5 dernières exécutions" + +#: src/ContainerDetails.jsx:71 +#, fuzzy +#| msgid "Checkpoint" +msgid "Latest checkpoint" +msgstr "Point de contrôle" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Conserver actif après la création du point de contrôle sur le disque" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Chargement des détails..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Chargement des logs..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Chargement..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Local" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Aucune image" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Journaux" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "Adresse MAC" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "Mo" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Nombre max de nouvellles tentatives" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Mémoire" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Limite mémoire" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Unité de mémoire" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Mode" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Plusieurs tags existent pour cette image. Sélectionnez les images marquées à " +"supprimer." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Nom" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Nouveau nom du conteneur" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Nom de la nouvelle image" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Non" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Pas d'action" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Aucun conteneur" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Aucun conteneur n’utilise cette image" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Aucun conteneur dans ce pod" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Aucun conteneur ne correspond au filtre actuel" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Aucune variables d’environnement spécifiée" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Aucune image" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Aucune image trouvée" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Aucune image ne correspond au filtre actuel" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Pas de label" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Aucuns ports exposés" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Aucun résultat pour $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Aucun conteneur en cours d’exécution" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Aucuns volumes spécifiés" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "En cas d’échec" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "En cours d’exécution seulement" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Options" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Propriétaire" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Aide au propriétaire" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Bilan de fonctionnement réussi" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Collez une ou plusieurs lignes de paires clé=valeur dans n'importe quel " +"champ pour une importation en masse" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Pause" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Mettre le conteneur en pause lors de la création de l’image" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "En pause" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Échec de la création du pod" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Nom du pod" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Conteneurs Docker" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Le service Docker n’est pas actif" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Mappage de port" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Ports" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Les ports inférieurs à 1024 peuvent être mappés" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Privé" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protocole" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Suppression de certaines images" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +#, fuzzy +#| msgid "Prune unused images" +msgid "Prune unused containers" +msgstr "Suppression d’images non utilisées" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Suppression d’images non utilisées" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +#, fuzzy +#| msgid "No running containers" +msgid "Pruning containers" +msgstr "Aucun conteneur en cours d’exécution" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Suppression de certaines images" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Extraire la dernière image" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Extraction" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Accès en lecture seule" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Accès en lecture-écriture" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Supprimer l'élément" + +#: src/PruneUnusedContainersModal.jsx:99 +#, fuzzy +#| msgid "Images and running containers" +msgid "Removes selected non-running containers" +msgstr "Images et conteneurs en cours d’exécution" + +#: src/util.js:23 +msgid "Removing" +msgstr "En cours de suppression" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Renommer" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Renommer le conteneur $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Des limites de ressources peuvent être fixées" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Redémarrer" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Redémarrer la stratégie" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Assistance pour la politique de redémarrage" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Politique de redémarrage à suivre lors de la sortie des conteneurs." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Politique de redémarrage à suivre lorsque les conteneurs se terminent. " +"L'utilisation de linger pour le démarrage automatique des conteneurs peut ne " +"pas fonctionner dans certaines circonstances, comme lorsque ecryptfs, " +"systemd-homed, NFS ou 2FA sont utilisés sur un compte utilisateur." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Restaurer" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Restaurer le conteneur $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Restaurer avec les connexions TCP établies" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Limité par les autorisations du compte de l'utilisateur" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Reprendre" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Tentatives" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Nouvelle tentative sur autre term." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Exécuter le bilan de fonctionnement" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "En fonctionnement" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Rechercher par nom ou description" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Recherche par registre" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Rechercher" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Chercher une image" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Chaîne de recherche ou emplacement du conteneur" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Recherche en cours..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Recherche en cours : $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Partagé" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Afficher" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Afficher les images" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Afficher les images intermédiaires" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Afficher moins de détails" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Montrer plus" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Taille" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Démarrer" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Période de démarrage" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Démarrer docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Commencez à saisir les données pour rechercher des images." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Commencé à" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "État" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Statut" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Arrêter" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Arrêté" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Prendre en charge le maintien des connexions TCP établies" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Système" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Le service Docker est également disponible" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Tag" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Étiquettes" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "L’interface utilisateur Cockpit pour les conteneur Docker." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Le temps d'initialisation nécessaire à l'amorçage d'un conteneur." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Le temps maximum autorisé pour compléter le contrôle de fonctionnement avant " +"qu'un intervalle soit considéré comme ayant échoué." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Le nombre de tentatives autorisées avant qu'un contrôle de fonctionnement ne " +"soit considéré non acceptable." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Délai d'attente" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Dépannage" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Entrez pour filtrer…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Impossible de charger l'historique des images" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Non acceptable" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "En cours d’exécution depuis $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Utiliser l'ancien format Docker" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Utilisé par" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Utilisateur" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Le service utilisateur Docker est également disponible" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Utilisateur :" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Valeur" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Volumes" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "En cas d'insalubrité" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Avec le terminal" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Accessible en écriture" + +#: src/manifest.json:0 +msgid "container" +msgstr "conteneur" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "En cours de téléchargement" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:port]/[user]/container[:tag]" + +#: src/manifest.json:0 +msgid "image" +msgstr "image" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "dans" + +#: src/ImageDeleteModal.jsx:79 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate" +msgstr "Cacher les images intermédiaires" + +#: src/ImageDeleteModal.jsx:59 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate image" +msgstr "Cacher les images intermédiaires" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "n. d." + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "non disponible" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "groupe pod" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "ports" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "secondes" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "système" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "non utilisé" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "utilisateur :" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "volumes" + +#~ msgid "Delete $0" +#~ msgstr "Supprimer $0" + +#~ msgid "select all" +#~ msgstr "tout sélectionner" + +#~ msgid "Restarting" +#~ msgstr "Redémarrage" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Confirmer la suppression de $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Confirmer la suppression du pod $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Confirmer la suppression forcée du pod $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Confirmer la suppression forcée de $0" + +#~ msgid "Container is currently running." +#~ msgstr "Le conteneur est actuellement en cours d’exécution." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "" +#~ "Ne pas inclure les changements effectués sur la racine du système de " +#~ "fichier lors de l'export" + +#~ msgid "Default with single selectable" +#~ msgstr "Par défaut avec sélection simple" + +#~ msgid "Start after creation" +#~ msgstr "Démarrer après création" + +#, fuzzy +#~| msgid "Delete tagged images" +#~ msgid "Delete unused $0 images:" +#~ msgstr "Supprimer les images taguées" + +#~ msgid "created" +#~ msgstr "créé" + +#~ msgid "exited" +#~ msgstr "Quittés" + +#~ msgid "paused" +#~ msgstr "Mis en pause" + +#~ msgid "running" +#~ msgstr "en cours d'exécution" + +#~ msgid "stopped" +#~ msgstr "arrêté" + +#, fuzzy +#~| msgid "user:" +#~ msgid "user" +#~ msgstr "utilisateur :" + +#~ msgid "Add on build variable" +#~ msgstr "Ajouter une variable de build" + +#~ msgid "Commit image" +#~ msgstr "Valider image" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Message" +#~ msgstr "Message" + +#~ msgid "Pause the container" +#~ msgstr "Mettre le conteneur en pause" + +#~ msgid "Remove on build variable" +#~ msgstr "Supprimer la variable de construction" + +#~ msgid "Set container on build variables" +#~ msgstr "Définir le conteneur sur les variables de construction" + +#~ msgid "Add item" +#~ msgstr "Ajouter un élément" + +#~ msgid "Host port (optional)" +#~ msgstr "Port de l’hôte (optionnel)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (optionnel)" + +#~ msgid "ReadOnly" +#~ msgstr "LectureSeule" + +#~ msgid "IP prefix length" +#~ msgstr "Taille du préfixe IP" + +#~ msgid "Get new image" +#~ msgstr "Obtenir une nouvelle image" + +#~ msgid "Run" +#~ msgstr "Exécuter" + +#~ msgid "On build" +#~ msgstr "En construction" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Voulez-vous vraiment supprimer cette image ?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Impossible de s’attacher à ce conteneur : $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Impossible d’ouvrir le canal : $0" + +#~ msgid "Everything" +#~ msgstr "Tout" + +#~ msgid "Security" +#~ msgstr "Sécurité" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "L’analyse de $time ($type) n’a trouvé aucune vulnérabilité." + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "" +#~ "Cette version de la console web n’est compatible avec les terminaux." diff --git a/ui/cockpit-docker/po/ja.po b/ui/cockpit-docker/po/ja.po new file mode 100644 index 0000000..dd5e9ba --- /dev/null +++ b/ui/cockpit-docker/po/ja.po @@ -0,0 +1,1467 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2024-02-19 03:30+0000\n" +"Last-Translator: Mie Yamamoto \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0\n" +"X-Generator: Weblate 5.4\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 コンテナー" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 イメージ合計、$1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 2 番目" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 の未使用イメージ、$1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 - 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "コンテナーが異常な状態に移行したときに実行するアクション。" + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "ポートマッピングの追加" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "変数の追加" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "ボリュームの追加" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "すべて" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "すべてのレジストリー" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "常時" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "エラーが発生しました" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "作成者" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "起動時に docker を自動的に起動する" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU share のヘルプ" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU 共有" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU 共有は実行中のコンテナーの優先度を決定します。デフォルトの優先度は 1024 " +"です。数値が高いほど、このコンテナーの優先度が高くなります。数値が低いほど優" +"先度が低くなります。" + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "取り消し" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "ヘルスチェック" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "チェックポイント" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "チェックポイントおよび復元のサポート" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "チェックポイントコンテナー $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "クリックして公開されたポートを表示します" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "クリックしてボリュームを表示します" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Docker コンテナーの Cockpit コンポーネント" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "コマンド" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "コメント" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "コミット" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "コンテナーのコミット" + +#: src/util.js:23 +msgid "Configured" +msgstr "設定済み" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "コンソール" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "コンテナー" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "コンテナーの作成に失敗しました" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "コンテナーの開始に失敗しました" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "コンテナーが実行されていません" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "コンテナー名" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "コンテナー名が必要です。" + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "コンテナーパス" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "コンテナーパスは空欄にできません" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "コンテナーポート" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "コンテナーポートは空欄にできません" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "コンテナー" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "作成" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "$0 コンテナーの現在の状態に基づいて、新しいイメージを作成します。" + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "作成して実行する" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "コンテナーの作成" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "$0 でのコンテナーの作成" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Pod でのコンテナーの作成" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Pod の作成" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "作成済み" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "作成元" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "CPU 共有を減らす" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "間隔を縮小する" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "最大再試行回数を減らす" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "メモリーを減らす" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "再試行回数を減らす" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "開始期間を縮小する" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "タイムアウトを縮小する" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "削除" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "$0 イメージを削除しますか?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "$0 を削除しますか?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "イメージの削除" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Pod $0 を削除しますか?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "タグ付けされたイメージの削除" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "使用されていないシステムイメージの削除:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "使用されていないユーザーイメージの削除:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "コンテナーを削除すると、コンテナー内のすべてのデータが削除されます。" + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "実行中のコンテナーを削除すると、その中のすべてのデータが削除されます。" + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "この Pod を削除すると、以下のコンテナーが削除されます:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "詳細" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "ディスクの空き容量" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Dockerフォーマットは、イメージをDockerまたはMoby Engineで共有する時に便利です" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "ダウンロード" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "新規イメージのダウンロード" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "空の Pod $0 は完全に削除されます。" + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "エントリーポイント" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "環境変数" + +#: src/util.js:26 +msgid "Error" +msgstr "エラー" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "エラーメッセージ" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "コンソールへの接続中にエラーが発生しました" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "例: 名前 " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "例: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "終了" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "失敗したヘルスの実行" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "コンテナー $0 のチェックポイントに失敗しました" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "コンテナーのクリーンアップに失敗しました" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "コンテナー $0 のコミットに失敗しました" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "コンテナー $0 の作成に失敗しました" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "イメージ $0 のダウンロードに失敗しました: $1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "コンテナー $0 を強制的に削除できませんでした" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "イメージ $0 の強制削除に失敗しました" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Pod $0 の強制再起動に失敗しました" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Pod $0 の強制停止に失敗しました" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "コンテナー $0 の一時停止に失敗しました" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Pod $0 の一時停止に失敗しました" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "使用されていないイメージの prune に失敗しました" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "使用されていないイメージのpruneに失敗しました" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "イメージ $0 のpullに失敗しました" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "コンテナー $0 の削除に失敗しました" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "イメージ $0 の削除に失敗しました" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "コンテナーの名前変更に失敗しました $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "コンテナー $0 の再起動に失敗しました" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Pod $0 の再起動に失敗しました" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "コンテナー $0 の復元に失敗しました" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "コンテナー $0 のレジュームに失敗しました" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Pod $0 の再開に失敗しました" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "コンテナー $0 の実行に失敗しました" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "コンテナーでのヘルスチェックの実行に失敗しました $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "イメージの検索に失敗しました。" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "イメージの検索に失敗しました: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "新規イメージの検索に失敗しました" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "コンテナー $0 の起動に失敗しました" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Pod $0 の起動に失敗しました" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "コンテナー $0 の停止に失敗しました" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Pod $0 の停止に失敗しました" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "失敗の連続" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "強制コミット" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "削除の強制" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Pod $0 を強制的に削除しますか?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "再起動の強制" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "停止の強制" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "ゲートウェイ" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "ヘルスチェック" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "ヘルスチェックの間隔のヘルプ" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "ヘルスチェックの再試行のヘルプ" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "ヘルスチェックの開始期間のヘルプ" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "ヘルスチェックのタイムアウトのヘルプ" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "ヘルスチェック失敗時のアクションのヘルプ" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "健全" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "イメージを非表示" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "中間イメージを非表示" + +#: src/Images.jsx:158 +msgid "History" +msgstr "履歴" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "ホストパス" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "ホストポート" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "ホストポートヘルプ" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP アドレス" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "IP アドレスヘルプ" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "開発に最適" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "実行中のサービスに最適" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"ホスト IP を 0.0.0.0 に設定した場合、またはまったく設定しなかった場合、ポート" +"はホスト上のすべての IP にバインドされます。" + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"ホストポートが設定されていない場合、コンテナーポートにはホストのポートがラン" +"ダムに割り当てられます。" + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "静的に設定された場合は IP アドレスを無視" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "静的に設定された場合は MAC アドレスを無視" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "イメージ" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "イメージ名は一意ではありません" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "イメージ名が必要です" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "イメージ選択のヘルプ" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "イメージ" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "CPU 共有を増やす" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "間隔を増やす" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "最大再試行回数を増やす" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "メモリーを増やす" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "再試行を増やす" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "開始期間を拡大する" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "タイムアウトを拡大する" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "インテグレーション" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "間隔" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "ヘルスチェックの実行頻度 (間隔)。" + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"無効な文字です。名前には文字、数字、および特定の句読点 (_ . -) のみを使用でき" +"ます。" + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "すべての一時的なチェックポイントファイルを維持" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "キー" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "キーは空欄にできません" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "過去 5 回の実行" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "最終チェックポイント" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "チェックポイントをディスクに書き込む後もそのまま実行したままにする" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "詳細をロード中..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "ログをロード中..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "ロード中..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "ローカル" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "ローカルのイメージ" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "ログ" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC アドレス" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "最大施行数" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "メモリ" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "メモリー制限" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "メモリーユニット" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "モード" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"このイメージには、複数のタグが存在します。削除するタグ付けされたイメージを選" +"択します。" + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "有効な IP アドレスにしてください" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "名前" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "名前はすでに使用中です" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "新しいコンテナー名" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "新しいイメージ名" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "いいえ" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "アクションなし" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "コンテナーなし" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "このイメージを使用するコンテナーはありません" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "この Pod 内のコンテナーはありません" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "現在のフィルターに一致するコンテナーがありません" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "環境変数が指定されていません" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "イメージなし" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "イメージが見つかりません" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "現在のフィルターに一致するイメージがありません" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "ラベルなし" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "開放されているポートはありません" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "$0 の結果なし" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "実行中のコンテナーはありません" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "指定されているボリュームはありません" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "障害発生時" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "実行のみ" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "オプション" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "所有者" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "所有者のヘルプ" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "合格したヘルスの実行" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"一括インポートのために、キー=値ペアからなる 1 つまたは複数の行を任意のフィー" +"ルドに貼り付けます" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "一時停止" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "イメージの作成時にコンテナーを一時停止します" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "一時停止" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Pod の作成に失敗しました" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Pod 名" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker コンテナー" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker サービスがアクティブではありません" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "ポートマッピング" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "ポート" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "1024 未満のポートをマッピングできます" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "プライベート" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "プロトコル" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "削除" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "使用していないコンテナーの削除" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "未使用イメージの削除" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "コンテナーに prune を実行中" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "イメージを削除中" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "最新イメージのプル" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "プル中" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "読み取り専用アクセス" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "読み書きアクセス" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "アイテムの削除" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "選択した実行中でないコンテナーを削除します" + +#: src/util.js:23 +msgid "Removing" +msgstr "削除中" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "名前変更" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "コンテナーの名前変更 $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "リソース制限を設定できます" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "再起動" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "再起動ポリシー" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "再起動ポリシーのヘルプ" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "コンテナーの終了時に従う再起動ポリシー。" + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"コンテナーの終了時に従う再起動ポリシー。コンテナーの自動起動に linger を使用" +"すると、ユーザーアカウントで ecryptfs、systemd-homed、NFS、または 2FA が使用" +"されている場合など、一部の状況では機能しない場合があります。" + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "復元" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "コンテナー $0 の復元" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "確立された TCP 接続での復元" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "ユーザーアカウントのパーミッションによって制限" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "再開" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "再試行回数" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "別の用語を再試行します。" + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "ヘルスチェックを実行する" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "実行中" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "名前または説明による検索" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "レジストリーで検索" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "検索" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "イメージの検索" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "検索文字列またはコンテナーのロケーション" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "検索中..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "検索中: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "共有" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "表示" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "イメージの表示" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "中間イメージの表示" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "簡易表示" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "詳細表示" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "サイズ" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "開始" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "開始期間" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Docker を起動" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "イメージを検索するために入力を開始します。" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "開始日時" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "状態" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "ステータス" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "停止" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "停止中" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "確立された TCP 接続の保持サポート" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "システム" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "システム Docker サービスも利用できます" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "タグ" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "タグ" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Docker コンテナーの Cockpit ユーザーインターフェイス。" + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "コンテナーのブートストラップに必要な初期化時間。" + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"間隔が失敗したとみなされる前に、ヘルスチェックを完了するために許容される最大" +"時間。" + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "ヘルスチェックが異常であると見なされるまでに許可される再試行の回数。" + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "タイムアウト" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "トラブルシュート" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "入力してフィルタリング…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "イメージ履歴をロードできません" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "異常" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "$0 から稼働中" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "レガシーの Docker フォーマットの使用" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "使用中" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "ユーザー" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "ユーザーの Docker サービスも利用できます" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "ユーザー:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "値" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "ボリューム" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "異常な場合" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "端末の使用" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "書き込み可能" + +#: src/manifest.json:0 +msgid "container" +msgstr "コンテナー" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "ダウンロード中" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:port]/[user]/container[:tag]" + +#: src/manifest.json:0 +msgid "image" +msgstr "イメージ" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "場所" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "中間" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "中間イメージ" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "N/A" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "利用できません" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "Pod グループ" + +#: src/manifest.json:0 +msgid "docker" +msgstr "Docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "ポート" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "秒" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "システム" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "未使用" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "ユーザー:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "ボリューム" + +#~ msgid "Delete $0" +#~ msgstr "$0 の削除" + +#~ msgid "select all" +#~ msgstr "すべて選択" + +#~ msgid "Restarting" +#~ msgstr "再起動中" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "$0 の削除を確定する" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Pod $0 の削除を確定する" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Pod $0 の強制削除を確定する" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "$0 の強制削除を確定する" + +#~ msgid "Container is currently running." +#~ msgstr "コンテナーは現在実行中です。" + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "エクスポート時に root ファイルシステムの変更を含めないでください" + +#~ msgid "Default with single selectable" +#~ msgstr "単一項目のみ選択可能なデフォルト" + +#~ msgid "Start after creation" +#~ msgstr "作成後に開始" + +#, fuzzy +#~| msgid "Delete tagged images" +#~ msgid "Delete unused $0 images:" +#~ msgstr "タグ付けされたイメージの削除" + +#~ msgid "created" +#~ msgstr "作成済み" + +#~ msgid "exited" +#~ msgstr "終了" + +#~ msgid "paused" +#~ msgstr "一時停止" + +#~ msgid "running" +#~ msgstr "実行中" + +#~ msgid "stopped" +#~ msgstr "停止中" + +#, fuzzy +#~| msgid "user:" +#~ msgid "user" +#~ msgstr "ユーザー:" + +#~ msgid "Add on build variable" +#~ msgstr "ビルド変数の追加" + +#~ msgid "Commit image" +#~ msgstr "イメージのコミット" + +#~ msgid "Format" +#~ msgstr "フォーマット" + +#~ msgid "Message" +#~ msgstr "メッセージ" + +#~ msgid "Pause the container" +#~ msgstr "コンテナーの一時停止" + +#~ msgid "Remove on build variable" +#~ msgstr "ビルド変数の削除" + +#~ msgid "Set container on build variables" +#~ msgstr "ビルド変数にコンテナーを設定する" + +#~ msgid "Add item" +#~ msgstr "アイテムの追加" + +#~ msgid "Host port (optional)" +#~ msgstr "ホストポート (オプション)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (任意)" + +#~ msgid "ReadOnly" +#~ msgstr "読み取り専用" + +#~ msgid "IP prefix length" +#~ msgstr "IP プレフィックスの長さ" + +#~ msgid "Run" +#~ msgstr "実行" diff --git a/ui/cockpit-docker/po/ka.po b/ui/cockpit-docker/po/ka.po new file mode 100644 index 0000000..3737c90 --- /dev/null +++ b/ui/cockpit-docker/po/ka.po @@ -0,0 +1,1408 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-11-29 13:31+0000\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 5.2.1\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 ცალი კონტეინერი" +msgstr[1] "$0 კონტეინერი" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 ცალი გამოსახულება, $1" +msgstr[1] "$0 გამოსახულება, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 წამი" +msgstr[1] "$0 წამი" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 ცალი გამოუყენებელი გამოსახულება, $1" +msgstr[1] "$0 გამოუყენებელი გამოსახულება, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1-დან 65535-მდე" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" +"ქმედება, რომელიც კონტეინერის არაჯანმრთელ მდომარეობაში გადასვლისას შესრულდება." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "პორტის ასახვის დამატება" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "ცვლადის დამატება" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "საცავის დამატება" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "ყველა" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "ყველა რეგისტრები" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "ყველთვის" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "შეცდომა" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "ავტორი" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "docker-ის გაშვება სისტემის ჩატვირთვისას" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "პროცესორი" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "პროცესორის გაზიარების დახმარება" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU გაზიარება" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU-ის ზიარები განსაზღვრავენ გაშვებულიკონტეინერების პრიორიტეტს. ნაგულისხმები " +"პრიორიტეტი 1024-ის ტოლია. რაც მეტია რიცხვი, მით მეტია პრიორიტეტი; რაც " +"ნაკლები -ნაკლები." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "გაუქმება" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "ჯანმრთელობის შემოწმება" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "საკონტროლო წერტილი" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "საკონტროლო წერტილის და აღდგენის მხარდაჭერა" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "საკონტროლო წერტილის კონტეინერი ($0)" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "დააწკაპუნეთ გამოჩენილი პორტების სანახავად" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "დააწკაპუნეთ ტომების სანახავად" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Cockpit-ის კომპონენტი Docker-ის კონტეინერებისთვის" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "ბრძანება" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "კომენტარები" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "გადაცემა" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "კონტეინერის გაგზავნა" + +#: src/util.js:23 +msgid "Configured" +msgstr "მორგებულია" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "კონსოლი" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "კონტეინერი" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "კონტეინერის შექმნის შეცდომა" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "კონტეინერის გაშვების შეცდომა" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "კონტეინერი გაშვებული არაა" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "კონტეინერის სახელი" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "კონტეინერის სახელი აუცილებელია." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "კონტეინერის ბილიკი" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "კონტეინერის ბილიკი არ შეიძლება ცარიელი იყოს" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "კონტეინერის პორტი" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "კონტეინერის პორტი არ შეიძლება ცარიელი იყოს" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "კონტეინერები" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "შექმნა" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "კონტეინერის ($0) მდგომარეობაზე დამყარებული ახალი გამოსახულების შექმნა." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "შექმნა და გაშვება" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "კონტეინერის შექმნა" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "$0-ში კონტეინერის შექმნა" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "pod-ში კონტეინერის შექმნა" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "pod-ის შექმნა" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "შექმნილია" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "ავტორი" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "CPU გაზიარებების შემცირება" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "ინტერვალის შემცირება" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "ცდების მაქსიმალური რაოდენობის შემცირება" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "მეხსიერების შემცირება" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "ცდების რაოდენობის შემცირება" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "გაშვების პერიოდის შემცირება" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "მოლოდინის დროის შემცირება" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "წაშლა" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "წავშალო $0 დისკის ასლი?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "წავშალო $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "დისკის ასლის წაშლა" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "წავშალო პოდი $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "ჭდეებიანი გამოსახულებების წაშლა" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "სისტემის გამოუყენებელი გამოსახულებების წაშლა:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "მომხმარებლის გამოუყენებელი გამოსახულებების წაშლა:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "კონტეინერის წაშლა მასში ყველა მონაცემს წაშლის." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "გაშვებული კონტეინერის წაშლა მასში ყველა მონაცემს წაშლის." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "ამ Pod-ის წაშლა ასევე წაშლის შემდეგ კონტეინერებს:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "დეტალები" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "ადგილი დისკზე" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Docker-ის ფორმატი ძალიან სასარგებლოა გამოსახულების Docker-თან ან Moby " +"Engline-სთან გაზიარებისთვის" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "გადმოწერა" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "ახალი გამოსახულების გადმოწერა" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "ცარიელი პოდი $0 სამუდამოდ წაიშლება." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "შესავალი წერტილი" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "გარემოს ცვლადები" + +#: src/util.js:26 +msgid "Error" +msgstr "შეცდომა" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "შეცდომის შეტყობინება" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "კონსოლთან დაკავშირების შეცდომა" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "მაგ. თქვენი სახელი " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "მაგალითად: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "გამოსული" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "ჯანმრთელობის შემოწმების შეცდომა" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "კონტეინერის ($0) საკონტროლო წერტილის შეცდომა" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "კონტეინერის გასუფთავების შეცდომა" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "კონტეინერის ($0) გადაცემის შეცდომა" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "კონტეინერის ($0) შექმნის შეცდომა" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "გამოსახულების ($0) გადმოწერის შეცდომა: $1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "კონტეინერის ($0) წაშლის შეცდომა" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "გამოსახულების ($0) ძალით წაშლა შეუძლებელია" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Pod-ის ($0) ძალით რესტარტის შეცდომა" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Pod-ის ($0) ძალით გაჩერების შეცდომა" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "კონტეინერის ($0) შეჩერების შეცდომა" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Pod-ის ($0) შეჩერების შეცდომა" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "გამოუყენებელი კონტეინერების წაკვეთის შეცდომა" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "გამოუყენებელი გამოსახულებების წაკვეთის შეცდომა" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "გამოსახულების ($0) გამოთხოვნის შეცდომა" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "კონტეინერის ($0) წაშლის შეცდომა" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "გამოსახულების ($0) წაშლის შეცდომა" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "კონტეინერის ($0) სახელის გადარქმევის შეცდომა" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "კონტეინერის ($0) რესტარტის შეცდომა" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Pod-ის ($0) რესტარტის შეცდომა" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "კონტეინერის ($0) აღდგენის შეცდომა" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "კონტეინერის ($0) გაგრძელების შეცდომა" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Pod-ის ($0) გაგრძელების შეცდომა" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "კონტეინერის ($0) გაშვების შეცდომა" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "კონტეინერის ($0) ჯანმრთელობის შემოწმების შეცდომა" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "გამოსახულებების ძებნის შეცდომა." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "გამოსახულების ძებნის შეცდომა: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "ახალი გამოსახულებების ძებნის შეცდომა" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "კონტეინერის ($0) გაშვების შეცდომა" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "pod-ს ($0) გაშვების შეცდომა" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "კონტეინერის ($0) გაჩერების შეცდომა" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "pod-ის ($0) გაჩერების შეცდომა" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "მრავალჯერადი წარუმატებლობა" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "ძალით გადაგზავნა" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "ძალით წაშლა" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "წავშლო ძალით პოდი $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "ძალით რესტარტი" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "ძალით გაჩერება" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "გბ" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "ნაგულისხმები რაუტერი" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "ჯანმრთელობის შემოწმება" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "ჯანმრთელობის შემოწმების ინტერვალის დახმარება" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "ჯანმრთელობის შემოწმების ცდების რაოდენობის დახმარება" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "ჯანმრთელობის შემოწმების გაშვების პერიოდის დახმარება" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "ჯანმრთელობის შემოწმების ვადის დახმარება" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "ჯანმრთელობის შემოწმების ქმედების დახმარება" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "ჯანმრთელი" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "გამოსახულებების დამალვა" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "შუალედური გამოსახულებების დამალვა" + +#: src/Images.jsx:158 +msgid "History" +msgstr "ისტორია" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "ჰოსტის ბილიკი" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "ჰოსტის პორტი" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "დახმარება ჰოსტის პორტის შესახებ" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP მისამართი" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "დახმარება IP მისამართის შესახებ" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "იდეალურია პროგრამირებისთვის" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "იდეალურია სერვისების გასაშვებად" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"თუ ჰოსტის IP დაყენებულია 0.0.0.0-ზე ან საერთოდ არაა დაყენებული, პორტი ჰოსტზე " +"არსებულ ყველა IP-ს მიებმება." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"თუ ჰოსტის პორტი დაყენებული არაა, კონტეინერის პორტი ჰოსტზე შემთხვევითად " +"იქნება არჩეული." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "სტატიკურად მინიჭებული IP მისამართის იგნორი" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "სტატიკურად მინიჭებული MAC მისამართის იგნორი" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "გამოსახულება" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "ასლის სახელი უნიკალური არაა" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "ასლის სახელი აუცილებელია" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "დახმარება გამოსახულების არჩევის შესახებ" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "გამოსახულებები" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "CPU გაზიარებების გაზრდა" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "ინტერვალის გაზრდა" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "ცდების მაქსიმალური რაოდენობის გაზრდა" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "მეხსიერების გაზრდა" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "ცდების რაოდენობის გაზრდა" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "გაშვების პერიოდის გაზრდა" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "მოლოდინის დროის გაზრდა" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "ინტეგრაცია" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "ინტერვალი" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "ჯანმრთელობის შემოწმების გაშვების ინტერვალი." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"არასწორი სიმბოლოები. სახელი მხოლოდ ასოებს, ციფრებს და ზოგიერთ პუნქტუაციის " +"ნიშანს (_,-) შეიძლება შეიცავდეს." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "კბ" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "საკონტროლო წერტილის ყველა დროებითი ფაილის შენახვა" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "გასაღები" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "გასაღები არ შეიძლება, ცარიელი იყოს" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "ბოლო 5 გაშვება" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "უახლესი საკონტროლო წერტილი" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "საკონტროლო წერტილის დისკზე ჩაწერის შემდეგ გაშვებულად დატოვება" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "დეტალების ჩატვირთვა..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "ჟურნალის ჩატვირთვა..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "ჩატვირთვა..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "ლოკალური" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "ლოკალური გამოსახულებები" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "ჟურნალი" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC მისამართი" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "მბ" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "ცდების მაქსიმალური რაოდენობა" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "მეხსიერება" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "მეხსიერების ლიმიტი" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "მეხსიერების ერთეული" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "რეჟიმი" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"ამ გამოსახულებას მრავალი ჭდე გააჩნია. წასაშლელად მონიშნეთ ჭდეებიანი " +"გამოსახულებები." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "უნდა იყოს სწორი IP მისამართი" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "სახელი" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "სახელი უკვე გამოიყენება" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "ახალი კონტეინერის სახელი" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "ახალი გამოსახულების სახელი" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "არა" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "ქმედების გარეშე" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "კონტეიენერების გარეშე" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "ამ გამოსახულებას არცერთი კონტეინერი არ იყენებს" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "ამ Pod-ში კონტეინერები არაა" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "მიმდინარე ფილტრს არცერთი კონტეინერი არ შეესაბამება" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "გარემოს ცვლადი მითითებული არაა" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "გამოსახულებების გარეშე" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "გამოსახულებების გარეშე" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "მიმდინარე ფილტრს არცერთი გამოსახულება არ შეესაბამება" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "ჭდეების გარეშე" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "პორტები გამოტანილი არაა" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "პასუხების გარეშე $0-თვის" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "გაშვებული კონტეინერების გარეშე" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "საცავი მითითებული არაა" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "შეცდომისას" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "მხოლოდ გაშვებული" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "მორგება" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "მფლობელი" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "მფლობელის დახმარება" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "ჯანმრთელობის შემოწმება წარმატებულია" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"მრავალი შემოტანისთვის ველებში ჩასვით ერთი ან მეტი გასაღები=მნიშვნელობა-ის " +"ტიპის წყვილები" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "პაუზა" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "კონტეინერის შეჩერება გამოსახულების შექმნისას" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "შეჩერებულია" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Pod-ის შექმნის შეცდომა" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Pod-ის სახელი" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker-ის კონტეინერები" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker-ის სერვისი აქტიური არაა" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "პორტების ასახვა" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "პორტები" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "შეგიძლიათ 1024-ზე ნაკლები ნომრის მქონე პორტის მიბმა" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "პირადი" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "პროტოკოლი" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "შეკვეცა" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "გამოუყენებელი კონტეინერების წაკვეთა" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "გამოუყენებელი გამოსახულებების წაკვეთა" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "კონტეინერების წაკვეთა" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "გამოსახულებების წაკვეთა" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "უახლესი გამოსახულების წამოღება" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "გამოწევა" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "მხოლოდ-კითხვის წვდომა" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "ჩაწერა/წაკითხვის წვდომა" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "ელემენტის წაშლა" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "მონიშნული არა-გაშვებული კონტეინერების წაშლა" + +#: src/util.js:23 +msgid "Removing" +msgstr "წაშლა" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "გადარქმევა" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "კონტეინერის სახელის გადარქმევა ($0)" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "შეგიძლიათ ლიმიტების დაყენება" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "გადატვირთვა" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "რესტარტის წესები" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "დახმარება რესტარტის წესების შესახებ" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "კონტეინერების მუშაობის დასასრულისას რესტარტის წესები." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"კონტეინერების მუშაობის დასრულებისას მისაყოლი გადატვირთის პოლიტიკა. " +"კონტეინერების ავტომატური გაშვებისთვის linger-მა ყოველთვის შეიძლება არ " +"იმუშაოს. მაგალითად, თუ მომხმარებელზე enccryptfs, systemd-homed, NFS ან 2FA " +"გამოიყენება." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "აღდგენა" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "კონტეინერის აღდგენა ($0)" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "დამყარებული TCP კავშირებით აღდგენა" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "შეზღუდულია მომხმარებლის ანგარიშის წვდომებით" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "გაგრძელება" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "თავიდან ცდები" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "სხვა სიტყვა სცადეთ." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "ჯანმრთელობის შემოწმების გაშვება" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "გაშვებულია" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "სახელით ან აღწერით ძებნა" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "რეგისტრის ძებნა" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "ძებნა" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "გამოსახულების ძებნა" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "სტრიქონის ან კონტეინერის მდებარეობის ძებნა" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "ძებნა..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "ძებნა: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "გაზიარებული" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "ჩვენება" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "გამოსახულებების ჩვენება" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "შუალედური გამოსახულებების ჩვენება" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "ნაკლების ჩვენება" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "მეტის ჩვენება" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "ზომა" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "დაწყება" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "გაშვების პერიოდი" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Docker-ის გაშვება" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "გამოსახულებების მოსაძებნად დაიწყეთ მისი სახელის კრეფა." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "გაშვების დრო" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "მდგომარეობა" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "სტატუსი" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "გაჩერება" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "გაჩერებულია" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "დამყარებული TCP კავშირების შენარჩუნების მხარდაჭერა" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "სისტემა" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "ასევე ხელმისაწვდომია Docker-ის სისტემური სერვისი" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "ჭდე" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "ჭდეები" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Cockpit-ის მომხმარებლის ინტერფეისი Docker-ის კონტეინერებისთვის." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "კონტეინერის მოსარგებად საჭირო ინიციალიზაციის დრო." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"მაქსიმალური დრო ჯანმრთელობის შესამოწმებლად. ამ ინტერვალის გასვლის შემდეგ " +"შემოწმება შეცდომის მქონედ ითვლება." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"ცდების რაოდენობა, რის შემდეგაც ჯანმრთელობის შემოწმება ავარიულად ითვლება." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "დროის ამოწურვა" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "პრობლემების პოვნა" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "გაფილტვრისთვის აკრიფეთ…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "გამოსახულების ისტორიის ჩატვირთვის შეცდომა" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "ჯანმრთელი არაა" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "$0 და ზემოთ" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Docker-ის ძველი ფორმატის გამოყენება" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "გამოიყენება" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "მომხმარებელი" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "ასევე ხელმისაწვდომია Docker-ის მომხმარებლის სერვისი" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "მომხმარებელი:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "მნიშვნელობა" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "საცავები" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "როცა ჯანმრთელი არაა" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "ტერმინალით" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "ჩაწერადი" + +#: src/manifest.json:0 +msgid "container" +msgstr "კონტეინერი" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "გადმოწერა" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "ჰოსტი[:პორტი]/[მომხმარებელი]/კონტეინერი[:ჭდე]" + +#: src/manifest.json:0 +msgid "image" +msgstr "გამოსახულება" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "-ში" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "შუალედური" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "შუალედური დისკის ასლი" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "ა/მ" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "ხელმიუწვდომელია" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "pod-ების ჯგუფი" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "პორტები" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "წამი" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "სისტემა" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "გამოუყენებელი" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "მომხმარებელი:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "ტომები" + +#~ msgid "Delete $0" +#~ msgstr "$0-ის წაშლა" + +#~ msgid "select all" +#~ msgstr "ყველას მონიშვნა" + +#~ msgid "Failure action" +#~ msgstr "ქმედება ავარიისას" + +#~ msgid "Restarting" +#~ msgstr "გადატვირთვა" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "დაადასტურეთ $0-ის წაშლა" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "დაადასტურეთ Pod-ის წაშლა: $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "დაადასტურეთ pod-ის ძალით წაშლა: $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "დაადასტურეთ ძალით წაშლა: $0" + +#~ msgid "Container is currently running." +#~ msgstr "ამჟამად კონტეინერი გაშვებულია." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "გატანისას ფაილური სისტემის ცვლილებების არ-გადატანა" diff --git a/ui/cockpit-docker/po/ko.po b/ui/cockpit-docker/po/ko.po new file mode 100644 index 0000000..e21ae85 --- /dev/null +++ b/ui/cockpit-docker/po/ko.po @@ -0,0 +1,1461 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2024-03-16 15:35+0000\n" +"Last-Translator: 김인수 \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0\n" +"X-Generator: Weblate 5.4\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 컨테이너" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 이미지 총계, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 초" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 미사용 이미지, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 ~ 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "컨테이너가 비정상 상태로 전이되면 수행 할 작업." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "포트 대응을 추가합니다" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "변수를 추가합니다" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "볼륨 추가" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "모두" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "모든 레지스터리" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "항상" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "오류가 발생했습니다" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "작성자" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "부트시 자동으로 docker 시작" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU 공유 도움말" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU 공유" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU 공유는 동작 중인 콘테이너 우선 순위를 결정합니다. 기본 우선순위는 1024입" +"니다. 숫자가 클 수록 이 컨테이너 우선순위를 갖습니다. 낮은 번호는 우선 순위" +"가 낮아집니다." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "취소" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "상태 점검 중" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "점검점" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "점검점과 복구 지원" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "점검점 컨테이너 $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "공개된 포트를 보려면 누르세요" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "볼륨을 보려면 누르세요" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "포드맨 컨테이너를 위한 cockpit 구성요소" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "명령" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "주석" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "수행" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "컨테이너 커밋" + +#: src/util.js:23 +msgid "Configured" +msgstr "구성됨" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "콘솔" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "컨테이너" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "컨테이너 생성에 실패했습니다" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "컨테이너 시작에 실패했습니다" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "컨테이너가 동작 중이 아닙니다" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "컨테이너 이름" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "컨테이너 이름이 필요합니다." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "컨테이너 경로" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "컨테이너 경로는 비워두면 안됩니다" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "컨테이너 포트" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "컨테이너 포트는 비워두면 안됩니다" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "컨테이너" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "생성" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "$0 컨테이너의 현재 상태에서 기반된 새로운 이미지를 생성합니다." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "생성과 실행" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "컨테이너 생성" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "$0에서 컨테이너 생성" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "포드에서 컨테이너 생성" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "포드 생성" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "생성일" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "생성됨" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "CPU 공유 감소" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "간격 감소" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "최대 재시도 감소" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "메모리 감소" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "재시도 감소" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "시작 기간 감소" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "시간종료 감소" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "삭제" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "$0 이미지를 삭제할까요?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "$0 삭제?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "이미지 삭제" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "pod $0 삭제?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "태그가 지정된 이미지 삭제" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "사용하지 않는 시스템 이미지 삭제:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "사용하지 않는 사용자 이미지 삭제:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "컨테이너를 삭제는 내부의 모든 자료도 제거됩니다." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "동작 중인 컨테이너 삭제는 내부의 모든 자료도 제거됩니다." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "이 pod의 삭제는 다음 컨테이너도 제거될 것입니다:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "상세정보" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "디스크 공간" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"도커 형식은 도커 또는 모비 엔진과 같은 이미지를 공유 할 때에 유용합니다" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "내려받기" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "신규 이미지 내려받기" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "빈 pod $0는 영구적으로 제거됩니다." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "시작점" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "환경 변수" + +#: src/util.js:26 +msgid "Error" +msgstr "오류" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "오류 메시지" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "오류가 콘솔 연결 중에 발생했습니다" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "예제, 당신의 이름 " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "예제: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "종료됨" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "상태 실행에 실패함" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "컨테이너 $0 점검점에 실패" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "컨테이너를 정리하는데 실패" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "컨테이너 $0 수행에 실패" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "컨테이너 $0 생성에 실패" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "이미지 $0:$1 내려받기에 실패" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "컨테이너 $0 강제 제거에 실패" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "이미지 $0 강제 제거에 실패" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "pod $0 강제로 재시작 하는데 실패" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "pod $0 강제 멈춤에 실패" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "컨테이너 $0를 일시 중지 하는 데 실패" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "pod $0 일시정지에 실패" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "사용하지 않는 컨테이너 정리 실패" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "사용하지 않는 이미지 정리 실패" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "이미지 $0를 가져오는 데 실패" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "컨테이너 $0 제거에 실패" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "이미지 $0 제거에 실패" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "컨테이너 $0의 이름을 변경하는데 실패함" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "컨테이너 $0 재시작에 실패" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "pod $0 재시작에 실패" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "컨테이너 $0 복구에 실패" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "컨테이너 $0를 다시 시작 하는 데 실패" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "pod $0 재개에 실패" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "컨테이너 $0를 실행하는 데 실패" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "컨테이너 $0에서 상태를 점검하는데 실패함" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "이미지 검색을 실패함." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "이미지를 위한 검색 실패: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "새로운 이미지 검색 실패" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "컨테이너 $0 시작에 실패" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "pod $0를 시작하는 데 실패" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "컨테이너 $0 멈춤에 실패" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "pod $0 멈춤에 실패" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "연속 실패" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "강제 커밋" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "강제 삭제" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "pod $0 강제 삭제?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "강제 재시작" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "강제 멈춤" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "게이트웨이" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "상태 점검" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "상태 점검 간격 도움말" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "상태 점검 재시도 도움말" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "상태 점검 시작 기간 도움말" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "상태 점검 시간종료 도움말" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "상태 장애 점검 작용 도움말" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "상태좋음" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "이미지 숨김" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "중간 이미지 숨기기" + +#: src/Images.jsx:158 +msgid "History" +msgstr "기록" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "호스트 경로" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "호스트 포트" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "호스트 포트 도움말" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP 주소" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "IP 주소 도움말" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "개발을 위해 이상적인" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "실행 중인 서비스에 이상적인" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"만약 호스트 IP가 0.0.0.0으로 설정되거나 또는 전혀 설정되지 않으면, 포트는 호" +"스트의 모든 IP에서 묶이게 됩니다." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"만약 호스트 포트가 컨테이너에 설정되어 있지 않으면, 포트는 호스트에서 임의 지" +"정된 포트가 됩니다." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "정적인 상태라면 IP 주소 무시" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "정적인 상태라면 맥 주소 무시" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "이미지" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "이미지 이름은 독특하지 않습니다" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "이미지 이름이 필요합니다" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "이미지 선택 도움말" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "이미지" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "CPU 공유 증가" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "간격 증가" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "최대 재시도 증가" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "메모리 증가" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "재시도 증가" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "시작 기간 증가" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "시간종료 증가" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "통합" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "간격" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "얼마나 자주 상태 점검을 실행하는 간격." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"잘못된 문자. 이름은 문자, 수자와 특정 구두점(_ . -)만 포함 될 수 있습니다." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "모든 임시 점검점 파일을 유지합니다" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "키" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "키는 비워두면 안됩니다" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "최근 5회 실행" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "최신 점검점" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "점검점을 디스크에 쓰기 후에 계속 진행" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "세부정보 적재 중..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "기록 적재 중..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "적재 중..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "로컬" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "로컬 이미지" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "기록" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "맥(mac) 주소" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "최대 재시도" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "메모리" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "메모리 제한" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "메모리 장치" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "모드" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "다중 태그는 이 이미지에 존재합니다. 삭제에 태그된 이미지를 선택합니다." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "유효한 IP 주소이어야 합니다" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "이름" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "이미 사용 중인 이름입니다" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "신규 컨테이너 이름" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "신규 이미지 이름" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "아니오" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "반응 없음" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "컨테이너 없음" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "이 이미지에 사용 중인 컨테이너가 없습니다" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "이 포드에는 컨테이너가 없습니다" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "현재 필터에 일치하는 컨테이너가 없습니다" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "지정된 환경 변수가 없습니다" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "이미지 없음" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "이미지를 찾지 못했습니다" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "현재 필터에 일치하는 이미지가 없습니다" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "이름표가 없습니다" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "노출된 포트가 없습니다" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "$0의 결과를 찾을 수 없습니다" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "실행 중인 컨테이너가 없습니다" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "지정된 볼륨이 없습니다" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "실패한 경우" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "실행 만" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "옵션" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "소유자" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "소유자 도움말" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "상태 실행 통과됨" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"대량으로 가져오기 위해 키=값 쌍의 하나 이상의 행에 입력부분에 붙여 넣습니다" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "일시정지" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "이미지에 생성 중인 컨테이너를 일시 중지합니다" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "일시정지됨" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "포드 생성에 실패했습니다" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "포드 이름" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "포드맨" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "포드맨 컨테이너" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "포드맨 서비스가 동작하지 않습니다" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "포트 대응" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "포트" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "1024 이하 포트는 대응 될 수 있습니다" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "비공개" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "통신규약" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "프룬" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "사용하지 않은 컨테이너 정리" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "프룬 사용하지 않은 이미지" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "컨테이너 정리 중" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "프루닝 이미지" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "최신 이미지 가져오기" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "당기기" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "읽기-전용 접근" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "읽기-쓰기 접근" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "항목 제거" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "선택된 비-실행 컨테이너를 제거합니다" + +#: src/util.js:23 +msgid "Removing" +msgstr "제거 중" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "이름변경" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "컨테이너 $0 이름변경" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "자원 한계가 설정 될 수 있습니다" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "재시작" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "재시작 정책" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "정책 도움말 재시작" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "컨테이너를 종료 할 경우에 따라야 할 정책을 재시작 합니다." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"컨테이너가 종료 될 때 따라야 할 정책을 재시작합니다. 자동으로 시작하는 컨테이" +"너를 위한 linger를 사용은 ecryptfs, systemd-homed, NFS, 또는 2FA가 사용자 계" +"정에서 사용되는 것과 같이 특정 상황에서 작동하지 않을 수 있습니다." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "복구" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "컨테이너$0에서 복구" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "설정된 TCP 연결로 복구" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "사용자 계졍 권한에 의해 제한됨" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "다시 시작" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "재시도" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "다른 용어를 재시도." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "상태 점검을 실행" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "작동중" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "이름 또는 설명으로 찾기" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "레지스터리로 검색" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "찾기" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "이미지로 찾기" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "문자열 또는 컨테이너 위치 검색" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "검색 중..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "검색 중: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "공유됨" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "보기" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "이미지 보여주기" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "중간 이미지 보기" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "덜 보기" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "더 보기" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "크기" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "시작" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "시작 주기" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "포드맨 시작" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "이미지를 찾으려면 입력을 시작하세요." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "시작 시간" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "상태" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "상태" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "중지" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "정지됨" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "설정된 TCP 연결 유지 지원" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "시스템" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "시스템 포드맨 서비스도 사용 할 수 있습니다" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "꼬리표" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "꼬리표" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "포드맨 컨테이너를 위한 cockpit 사용자 연결장치." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "부트스트랩에서 컨테이너를 위해 필요한 초기화 시간." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"간격이 실패한 것으로 간주되기 전에 상태 점검을 완료하도록 허용되는 최대 시간." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "상태점검이 좋지 않은 것으로 고려되기 전에 허용되는 재시도 수." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "시간종료" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "문제 해결" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "필터 입력…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "이미지 기록을 적재 할 수 없음" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "상태나쁨" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "$0 이후 상승" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "레거시 도커 형식을 사용합니다" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "사용되었습니다" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "사용자" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "사용자 포드맨 서비스도 사용 할 수 있습니다" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "사용자:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "값" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "볼륨" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "상태나쁨" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "터미널 포함" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "쓰기 가능" + +#: src/manifest.json:0 +msgid "container" +msgstr "컨테이너" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "내려받기 중" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:포트]/[사용자]/컨테이너[:태그]" + +#: src/manifest.json:0 +msgid "image" +msgstr "이미지" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "in" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "중간" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "중간 이미지" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "해당 없음" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "사용할 수 없음" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "포드 그룹" + +#: src/manifest.json:0 +msgid "docker" +msgstr "포드맨" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "포트" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "초" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "systemd" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "미사용" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "사용자:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "볼륨" + +#~ msgid "Delete $0" +#~ msgstr "$0 삭제" + +#~ msgid "select all" +#~ msgstr "모두 선택" + +#~ msgid "Failure action" +#~ msgstr "장애 작용" + +#~ msgid "Restarting" +#~ msgstr "재시작하기" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "$0 삭제를 확인합니다" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "pod $0의 삭제를 확인합니다" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "pod $0의 강제 삭제를 확인합니다" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "$0의 강제된 삭제를 확인합니다" + +#~ msgid "Container is currently running." +#~ msgstr "컨테이너가 현재 실행 중입니다." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "내보내기 할 때에 root 파일-시스템 변경을 포함하지 마세요" + +#~ msgid "Default with single selectable" +#~ msgstr "단일 선택 가능한 기본값" + +#~ msgid "Start after creation" +#~ msgstr "생성 후에 시작" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "사용하지 않는 $0 이미지 삭제:" + +#~ msgid "created" +#~ msgstr "생성 됨" + +#~ msgid "exited" +#~ msgstr "종료됨" + +#~ msgid "paused" +#~ msgstr "일시 중지됨" + +#~ msgid "running" +#~ msgstr "실행 중" + +#~ msgid "stopped" +#~ msgstr "정지됨" + +#~ msgid "user" +#~ msgstr "사용자" + +#~ msgid "Add on build variable" +#~ msgstr "빌드 변수에 추가" + +#~ msgid "Commit image" +#~ msgstr "이미지 수행" + +#~ msgid "Format" +#~ msgstr "포멧" + +#~ msgid "Message" +#~ msgstr "메세지" + +#~ msgid "Pause the container" +#~ msgstr "컨테이너 일시중지" + +#~ msgid "Remove on build variable" +#~ msgstr "빌드 변수에서 제거" + +#~ msgid "Set container on build variables" +#~ msgstr "빌드 변수에 컨테이너 설정" + +#~ msgid "Add item" +#~ msgstr "항목 추가" + +#~ msgid "Host port (optional)" +#~ msgstr "호스트 경로(선택적)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (선택적)" + +#~ msgid "ReadOnly" +#~ msgstr "읽기 전용" + +#~ msgid "IP prefix length" +#~ msgstr "IP 프리픽스 길이" + +#~ msgid "Run" +#~ msgstr "실행" diff --git a/ui/cockpit-docker/po/pl.po b/ui/cockpit-docker/po/pl.po new file mode 100644 index 0000000..055a67b --- /dev/null +++ b/ui/cockpit-docker/po/pl.po @@ -0,0 +1,1508 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Piotr Drąg , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2024-02-23 19:36+0000\n" +"Last-Translator: Daviteusz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.4\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 kontener" +msgstr[1] "$0 kontenery" +msgstr[2] "$0 kontenerów" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 obraz, $1" +msgstr[1] "$0 obrazy razem, $1" +msgstr[2] "$0 obrazów razem, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 sekunda" +msgstr[1] "$0 sekundy" +msgstr[2] "$0 sekund" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 nieużywany obraz, $1" +msgstr[1] "$0 nieużywane obrazy, $1" +msgstr[2] "$0 nieużywanych obrazów, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 do 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "Działanie podejmowane po przejściu kontenera do niezdrowego stanu." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Dodaj mapowanie portów" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Dodaj zmienną" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Dodaj wolumin" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Wszystko" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Wszystkie rejestry" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Zawsze" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Wystąpił błąd" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Autor" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Automatyczne włączanie usługi docker podczas uruchamiania" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "Procesor" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Pomoc udziałów procesora" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Udziały procesora" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"Udziały procesora ustalają priorytety uruchomionych kontenerów. Domyślny " +"priorytet to 1024. Wyższa liczba zwiększa priorytet danego kontenera. " +"Mniejsza liczba zmniejsza priorytet." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Anuluj" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Sprawdzanie zdrowia" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Punkt kontrolny" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Obsługa punktu kontrolnego i przywracania" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Kontener punktu kontrolnego $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Kliknięcie wyświetli opublikowane porty" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Kliknięcie wyświetli woluminy" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Składnik Cockpit do kontenerów Docker" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Polecenie" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Komentarze" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Zatwierdź" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Zatwierdź kontener" + +#: src/util.js:23 +msgid "Configured" +msgstr "Skonfigurowane" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konsola" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Kontener" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Utworzenie kontenera się nie powiodło" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Uruchomienie kontenera się nie powiodło" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Kontener nie jest uruchomiony" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Nazwa kontenera" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Wymagana jest nazwa kontenera." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Ścieżka do kontenera" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "Ścieżka do kontenera nie może być pusta" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Port kontenera" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "Port kontenera nie może być pusty" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Kontenery" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Utwórz" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Utwórz nowy obraz na podstawie obecnego stanu kontenera $0." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Utwórz i uruchom" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Utwórz kontener" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Utwórz kontener w $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Utwórz kontener w pojemniku" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Utwórz pojemnik" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Utworzono" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Utworzony przez" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Zmniejsz udziały procesora" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Zmniejsz odstęp" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Zmniejsz maksymalną liczbę ponownych prób" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Zmniejsz pamięć" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Zmniejsz liczbę ponownych prób" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Zmniejsz okres uruchamiania" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Zmniejsz czas oczekiwania" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Usuń" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "Usunąć obraz $0?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Usunąć $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Usuń obraz" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Usunąć pojemnik $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Usuń oznaczone obrazy" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Usunięcie nieużywanych obrazów systemowych:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Usunięcie nieużywanych obrazów użytkownika:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "" +"Usunięcie kontenera spowoduje usunięcie wszystkich zawartych na nim danych." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "" +"Usunięcie uruchomionego kontenera spowoduje usunięcie wszystkich zawartych " +"na nim danych." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Usunięcie tego pojemnika spowoduje usunięcie tych kontenerów:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Szczegóły" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Miejsce na dysku" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Format Docker jest przydatny podczas udostępniania obrazu za pomocą Dockera " +"lub Moby Engine" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Pobierz" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Pobierz nowy obraz" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Pusty pojemnik $0 zostanie trwale usunięty." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Punkt wejścia" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Zmienne środowiskowe" + +#: src/util.js:26 +msgid "Error" +msgstr "Błąd" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Komunikat o błędzie" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Wystąpił błąd podczas łączenia konsoli" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Przykład, Imię Nazwisko " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Przykład: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Zakończono" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Niepomyślny wynik sprawdzania zdrowia" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Punkt kontrolny kontenera $0 się nie powiódł" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Wyczyszczenie kontenera się nie powiodło" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Zatwierdzenie kontenera $0 się nie powiodło" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Utworzenie kontenera $0 się nie powiodło" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Pobranie obrazu $0:$1 się nie powiodło" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Wymuszenie usunięcia kontenera $0 się nie powiodło" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Wymuszenie usunięcia obrazu $0 się nie powiodło" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Wymuszenie ponownego uruchomienia pojemnika $0 się nie powiodło" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Wymuszenie zatrzymania pojemnika $0 się nie powiodło" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Wstrzymanie kontenera $0 się nie powiodło" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Wstrzymanie pojemnika $0 się nie powiodło" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Wyczyszczenie nieużywanych kontenerów się nie powiodło" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Wyczyszczenie nieużywanych obrazów się nie powiodło" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Pobranie obrazu $0 się nie powiodło" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Usunięcie kontenera $0 się nie powiodło" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Usunięcie obrazu $0 się nie powiodło" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Zmiana nazwy kontenera $0 się nie powiodła" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Ponowne uruchomienie kontenera $0 się nie powiodło" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Ponowne uruchomienie pojemnika $0 się nie powiodło" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Przywrócenie kontenera $0 się nie powiodło" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Wznowienie kontenera $0 się nie powiodło" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Wznowienie pojemnika $0 się nie powiodło" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Uruchomienie kontenera $0 się nie powiodło" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Wykonanie sprawdzania zdrowia na kontenerze $0 się nie powiodło" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Wyszukanie obrazów się nie powiodło." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Wyszukanie obrazów się nie powiodło: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Wyszukanie nowych obrazów się nie powiodło" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Uruchomienie kontenera $0 się nie powiodło" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Uruchomienie pojemnika $0 się nie powiodło" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Zatrzymanie kontenera $0 się nie powiodło" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Zatrzymanie pojemnika $0 się nie powiodło" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Wielokrotne niepowodzenia" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Wymuś zatwierdzenie" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Wymuś usunięcie" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Wymusić usunięcie pojemnika $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Wymuś ponowne uruchomienie" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Wymuś zatrzymanie" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Brama" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Sprawdzanie zdrowia" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Pomoc odstępów między sprawdzaniem zdrowia" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Pomoc ponownych prób sprawdzania zdrowia" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Pomoc okresu uruchamiania sprawdzania zdrowia" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Pomoc czasu oczekiwania sprawdzania zdrowia" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Pomoc działania niepowodzenia sprawdzania zdrowia" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Zdrowy" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Ukryj obrazy" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Ukryj pośrednie obrazy" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historia" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Ścieżka do hosta" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Port hosta" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Pomoc portu hosta" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "Identyfikator" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "Adres IP" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Pomoc adresu IP" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Doskonałe dla programistów" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Doskonałe do uruchamiania usług" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Jeśli adres IP hosta jest ustawiony na 0.0.0.0 lub nie jest ustawiony, to " +"port będzie dowiązany do wszystkich adresów IP na hoście." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Jeśli port hosta nie jest ustawiony, to do portu kontenera będzie losowo " +"przydzielany port na hoście." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ignorowanie adresu IP, jeśli jest ustawiony statycznie" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ignorowanie adresu MAC, jeśli jest ustawiony statycznie" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Obraz" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Nazwa obrazu nie jest unikalna" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Nazwa obrazu jest wymagana" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Pomoc przy wyborze obrazu" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Obrazy" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Zwiększ udziały procesora" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Zwiększ odstęp" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Zwiększ maksymalną liczbę ponownych prób" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Zwiększ pamięć" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Zwiększ liczbę ponownych prób" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Zwiększ okres uruchamiania" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Zwiększ czas oczekiwania" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integracja" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Odstęp" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Odstęp między wykonywaniem sprawdzania zdrowia." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Nieprawidłowe znaki. Nazwa może zawierać tylko litery, cyfry i część znaków " +"interpunkcyjnych (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Przechowywanie wszystkich tymczasowych plików punktów kontrolnych" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Klucz" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "Klucz nie może być pusty" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Ostatnie 5 razy" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Najnowszy punkt kontrolny" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Bez wyłączania po zapisaniu punktu kontrolnego na dysku" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Wczytywanie szczegółów…" + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Wczytywanie dzienników…" + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Wczytywanie…" + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Lokalne" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Lokalne obrazy" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Dzienniki" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "Adres MAC" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Maksymalna liczba ponownych prób" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Pamięć" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Ograniczenie pamięci" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Jednostka pamięci" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Tryb" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Dla tego obrazu istnieje wiele etykiet. Proszę wybrać oznaczone obrazy do " +"usunięcia." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "Musi być prawidłowym adresem IP" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Nazwa" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Nazwa jest już używana" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Nowa nazwa kontenera" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Nazwa nowego obrazu" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Nie" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Brak działania" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Brak kontenerów" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Żadne kontenery nie używają tego obrazu" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Brak kontenerów w tym pojemniku" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Żadne kontenery nie pasują do obecnego filtru" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Nie podano zmiennych środowiskowych" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Brak obrazów" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Nie odnaleziono obrazów" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Żadne obrazy nie pasują do obecnego filtru" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Brak etykiety" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Brak eksponowanych portów" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Brak wyników dla zapytania „$0”" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Brak uruchomionych kontenerów" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Nie podano woluminów" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Przy niepowodzeniu" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Tylko uruchomione" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Opcje" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Właściciel" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Pomoc na temat właściciela" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Pomyślny wynik sprawdzania zdrowia" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Należy wkleić jeden lub więcej wierszy par klucz=wartość do dowolnego pola, " +"aby zaimportować hurtowo" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Wstrzymaj" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Wstrzymaj kontener podczas tworzenia obrazu" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Wstrzymane" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Utworzenie pojemnika się nie powiodło" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Nazwa pojemnika" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Kontenery Docker" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Usługa Docker nie jest aktywna" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Mapowanie portów" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Porty" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Można mapować porty poniżej 1024" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Prywatne" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokół" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Wyczyść" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Wyczyść nieużywane kontenery" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Wyczyść nieużywane obrazy" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Czyszczenie kontenerów" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Czyszczenie obrazów" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Pobierz najnowszy obraz" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Pobieranie" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Dostęp tylko do odczytu" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Dostęp do odczytu i zapisu" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Usuń element" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Usuwa zaznaczone nieuruchomione kontenery" + +#: src/util.js:23 +msgid "Removing" +msgstr "Usuwanie" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Zmień nazwę" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Zmień nazwę kontenera $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Można ustawić ograniczenia zasobów" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Uruchom ponownie" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Zasada ponownego uruchamiania" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Pomoc zasady ponownego uruchamiania" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Zasada ponownego uruchamiania używana podczas wyłączania kontenerów." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Zasada ponownego uruchamiania używana podczas wyłączania kontenerów. " +"Używanie zwlekania do automatycznego uruchamiania kontenerów może nie " +"działać w pewnych warunkach, takich jak podczas używania eCryptfs, systemd-" +"homed, NFS lub uwierzytelniania dwuskładnikowego na koncie użytkownika." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Przywróć" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Przywróć kontener $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Przywróć z nawiązanymi połączeniami TCP" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Ograniczone przez uprawnienia konta użytkownika" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Wznów" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Ponowne próby" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Spróbuj innych słów." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Wykonaj sprawdzanie zdrowia" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Uruchomione" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Szukaj według nazwy lub opisu" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Szukaj według rejestru" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Szukaj" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Znajdź obraz" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Szukaj ciągu lub położenia kontenera" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Wyszukiwanie…" + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Wyszukiwanie: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Współdzielone" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Wyświetl" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Wyświetl obrazy" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Wyświetl pośrednie obrazy" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Wyświetl mniej" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Wyświetl więcej" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Rozmiar" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Uruchom" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Okres uruchamiania" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Uruchom usługę docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Zacznij pisać, aby wyszukać obrazy." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Uruchomiono" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Stan" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Stan" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Zatrzymaj" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Zatrzymane" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Obsługa zachowywania nawiązanych połączeń TCP" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "System" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Dostępna jest także systemowa usługa Docker" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Etykieta" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Etykiety" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Interfejs Cockpit do kontenerów Docker." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Czas inicjacji wymagany do uruchomienia kontenera." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Maksymalny dozwolony czas na ukończenie sprawdzania zdrowia, zanim odstęp " +"jest uważany za niepomyślny." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Dozwolona liczba ponownych prób, zanim wynik sprawdzania zdrowia jest " +"uważany za niepomyślny." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Czas oczekiwania" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Rozwiąż problem" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Wyszukiwanie…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Nie można wczytać historii obrazu" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Niezdrowy" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Uruchomione od $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Przestarzały format Docker" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Używane przez" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Użytkownik" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Dostępna jest także usługa Docker użytkownika" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Użytkownik:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Wartość" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Woluminy" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Kiedy jest niezdrowy" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Z terminalem" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Zapisywalny" + +#: src/manifest.json:0 +msgid "container" +msgstr "kontener" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "pobieranie" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "komputer[:port]/[użytkownik]/kontener[:etykieta]" + +#: src/manifest.json:0 +msgid "image" +msgstr "obraz" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "w" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "pośredni" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "pośredni obraz" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "niedostępne" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "niedostępne" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "grupa pojemników" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "porty" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "s" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "systemowa" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "nieużywane" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "użytkownik:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "woluminy" + +#~ msgid "Delete $0" +#~ msgstr "Usuń $0" + +#~ msgid "select all" +#~ msgstr "zaznacz wszystko" + +#~ msgid "Failure action" +#~ msgstr "Działanie niepowodzenia" + +#~ msgid "Restarting" +#~ msgstr "Uruchamianie ponownie" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Potwierdź usunięcie $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Potwierdź usunięcie pojemnika $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Potwierdź wymuszenie usunięcia pojemnika $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Potwierdź wymuszenie usunięcia $0" + +#~ msgid "Container is currently running." +#~ msgstr "Kontener jest obecnie uruchomiony." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Bez dołączania zmian głównego systemu plików podczas eksportowania" + +#~ msgid "Default with single selectable" +#~ msgstr "Domyślne z jednym wyborem" + +#~ msgid "Start after creation" +#~ msgstr "Uruchom po utworzeniu" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Usunięcie nieużywanych obrazów $0:" + +#~ msgid "created" +#~ msgstr "utworzone" + +#~ msgid "exited" +#~ msgstr "zakończone" + +#~ msgid "paused" +#~ msgstr "wstrzymane" + +#~ msgid "running" +#~ msgstr "uruchomione" + +#~ msgid "stopped" +#~ msgstr "zatrzymane" + +#~ msgid "user" +#~ msgstr "użytkownika" + +#~ msgid "Add on build variable" +#~ msgstr "Dodaj na zmiennej budowania" + +#~ msgid "Commit image" +#~ msgstr "Zatwierdź obraz" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Message" +#~ msgstr "Komunikat" + +#~ msgid "Pause the container" +#~ msgstr "Wstrzymaj kontener" + +#~ msgid "Remove on build variable" +#~ msgstr "Usuń na zmiennej budowania" + +#~ msgid "Set container on build variables" +#~ msgstr "Ustaw kontener na zmiennych budowania" + +#~ msgid "Add item" +#~ msgstr "Dodaj element" + +#~ msgid "Host port (optional)" +#~ msgstr "Port gospodarza (opcjonalnie)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (opcjonalnie)" + +#~ msgid "ReadOnly" +#~ msgstr "Tylko do odczytu" + +#~ msgid "IP prefix length" +#~ msgstr "Długość przedrostka IP" + +#~ msgid "Get new image" +#~ msgstr "Pobierz nowy obraz" + +#~ msgid "Run" +#~ msgstr "Uruchom" + +#~ msgid "On build" +#~ msgstr "Podczas budowania" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Na pewno usunąć ten obraz?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Nie można dołączyć do tego kontenera: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Nie można otworzyć kanału: $0" + +#~ msgid "Everything" +#~ msgstr "Wszystko" + +#~ msgid "Security" +#~ msgstr "Zabezpieczenia" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "Wyszukiwanie z $time ($type) nie znalazło żadnych zagrożeń." + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "Ta wersja konsoli internetowej nie obsługuje terminala." diff --git a/ui/cockpit-docker/po/sk.po b/ui/cockpit-docker/po/sk.po new file mode 100644 index 0000000..657498e --- /dev/null +++ b/ui/cockpit-docker/po/sk.po @@ -0,0 +1,1553 @@ +# Matej Marusak , 2019. #zanata, 2020. +# Matej Marusak , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-11-13 13:37+0000\n" +"Last-Translator: Jose Riha \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" +"X-Generator: Weblate 5.1.1\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 kontajner" +msgstr[1] "$0 kontajnery" +msgstr[2] "$0 kontajnerov" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 obrazov dohromady, $1" +msgstr[1] "$0 obrazy dohromady, $1" +msgstr[2] "$0 obrazov dohromady, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 nepoužitých obrazov, $1" +msgstr[1] "$0 nepoužité obrazy, $1" +msgstr[2] "$0 nepoužitých obrazov, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Pridať mapovanie portov" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Pridať premennú" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Pridať zväzok" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Všetky" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Všetky registre" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Vždy" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Vyskytla sa chyba" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Autor" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Spúšťať docker pri zavádzaní systému" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +#, fuzzy +#| msgid "IP address" +msgid "CPU Shares help" +msgstr "IP adresa" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU podiely" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Zrušiť" + +#: src/Containers.jsx:286 +#, fuzzy +#| msgid "Checkpoint" +msgid "Checking health" +msgstr "Vytvoriť kontrolný bod" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Vytvoriť kontrolný bod" + +#: src/ImageRunModal.jsx:775 +#, fuzzy +#| msgid "Checkpoint container $0" +msgid "Checkpoint and restore support" +msgstr "Vytvoriť kontrolný bod pre kontajner $0" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Vytvoriť kontrolný bod pre kontajner $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "" + +#: org.cockpit-project.docker.metainfo.xml:6 +#, fuzzy +#| msgid "Docker containers" +msgid "Cockpit component for Docker containers" +msgstr "Docker kontajnery" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Príkaz" + +#: src/ImageHistory.jsx:33 +#, fuzzy +#| msgid "Commit" +msgid "Comments" +msgstr "Vytvoriť" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Vytvoriť" + +#: src/ContainerCommitModal.jsx:136 +#, fuzzy +#| msgid "No containers" +msgid "Commit container" +msgstr "Žiadne kontajnery" + +#: src/util.js:23 +msgid "Configured" +msgstr "Nakonfigurovaný" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konzola" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Kontajner" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Kontajner sa nepodarilo vytvoriť" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Kontajner sa nepodarilo spustiť" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Kontajner nebeží" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Názov kontajneru" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +#, fuzzy +#| msgid "Container name" +msgid "Container name is required." +msgstr "Názov kontajneru" + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Cesta v kontajneri" + +#: src/Volume.jsx:23 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container path must not be empty" +msgstr "Kontajner sa nepodarilo vytvoriť" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Port kontajneru" + +#: src/PublishPort.jsx:37 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container port must not be empty" +msgstr "Kontajner sa nepodarilo vytvoriť" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Kontajnery" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Vytvoriť" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "" + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Vytvoriť a spustiť" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Vytvoriť kontajner" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Vytvoriť kontajner v $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Vytvoriť kontajner v skupine" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +#, fuzzy +#| msgid "Created" +msgid "Create pod" +msgstr "Vytvorený" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Vytvorený" + +#: src/ImageHistory.jsx:33 +#, fuzzy +#| msgid "Created" +msgid "Created by" +msgstr "Vytvorený" + +#: src/ImageRunModal.jsx:939 +#, fuzzy +#| msgid "CPU shares" +msgid "Decrease CPU shares" +msgstr "CPU podiely" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "" + +#: src/ImageRunModal.jsx:978 +#, fuzzy +#| msgid "Maximum retries" +msgid "Decrease maximum retries" +msgstr "Maximum pokusov" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "" + +#: src/ImageRunModal.jsx:1099 +#, fuzzy +#| msgid "Start docker" +msgid "Decrease start period" +msgstr "Spustiť docker" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Odstrániť" + +#: src/ImageDeleteModal.jsx:92 +#, fuzzy +#| msgid "Delete $0" +msgid "Delete $0 image?" +msgstr "Odstrániť $0" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +#, fuzzy +#| msgid "Delete $0" +msgid "Delete $0?" +msgstr "Odstrániť $0" + +#: src/ImageDeleteModal.jsx:96 +#, fuzzy +#| msgid "Delete tagged images" +msgid "Delete image" +msgstr "Zmazať označené obrazy" + +#: src/PodActions.jsx:43 +#, fuzzy +#| msgid "Delete $0" +msgid "Delete pod $0?" +msgstr "Odstrániť $0" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Zmazať označené obrazy" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Zmazať nepoužívané systémové obrazy:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Zmazať nepoužívané užívateľské obrazy:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Zmazaním kontajneru sa zmažú všetky dáta v ňom." + +#: src/Containers.jsx:70 +#, fuzzy +#| msgid "Deleting a container will erase all data in it." +msgid "Deleting a running container will erase all data in it." +msgstr "Zmazaním kontajneru sa zmažú všetky dáta v ňom." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Zmazanie tohto podu zmaže nasledujúce kontajnery:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Podrobnosti" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Stiahnuť" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Stiahnuť nový obraz" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "" + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Vstupný bod" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Premenné prostredia" + +#: src/util.js:26 +msgid "Error" +msgstr "Chyba" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Chybová správa" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Príklad, Vaše Meno " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Príklad: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Skončený" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Nepodarilo sa vytvoriť kontrolný bod pre kontajner $0" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Nepodarilo sa zmazať kontajner" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Nepodarilo sa vytvoriť kontajner $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Nepodarilo sa stiahnuť obraz $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Nepodarilo sa vynútiť zmazanie kontajneru $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Nepodarilo sa vynútiť zmazanie obrazu $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Nepodarilo sa nútene reštartovať pod $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Nepodarilo sa vynútiť zmazanie podu $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Nepodarilo sa zastaviť kontajner $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Nepodarilo sa zastaviť pod $0" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Nepodarilo sa vyčistiť nepoužívané kontajnery" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Nepodarilo sa vyčistiť nepoužívané obrazy" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Nepodarilo sa stiahnuť obraz $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Nepodarilo sa zmazať kontajner $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Nepodarilo sa zmazať obraz $0" + +#: src/ContainerRenameModal.jsx:54 +#, fuzzy +#| msgid "Failed to resume container $0" +msgid "Failed to rename container $0" +msgstr "Nepodarilo sa spustiť kontajner $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Nepodarilo sa reštartovať kontajner $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Nepodarilo sa reštartovať pod $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Nepodarilo sa obnoviť kontajner $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Nepodarilo sa spustiť kontajner $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Nepodarilo sa znovuspustiť pod $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Nepodarilo sa spustiť kontajner $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +#, fuzzy +#| msgid "Failed to checkpoint container $0" +msgid "Failed to run health check on container $0" +msgstr "Nepodarilo sa vytvoriť kontrolný bod pre kontajner $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +#, fuzzy +#| msgid "Failed to search for images: $0" +msgid "Failed to search for images." +msgstr "Nepodarilo sa nájsť obrazy: $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Nepodarilo sa nájsť obrazy: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Nepodarilo sa nájsť nové obrazy" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Nepodarilo sa spustiť kontajner $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Nepodarilo sa spustiť pod $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Nepodarilo sa zastaviť kontajner $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Nepodarilo sa zastaviť pod $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "" + +#: src/ContainerCommitModal.jsx:151 +#, fuzzy +#| msgid "Force stop" +msgid "Force commit" +msgstr "Vynútiť zastavenie" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Vynútiť odstránenie" + +#: src/PodActions.jsx:42 +#, fuzzy +#| msgid "Force delete" +msgid "Force delete pod $0?" +msgstr "Vynútiť odstránenie" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Vynútiť reštartovanie" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Vynútiť zastavenie" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Brána" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Skryť obrazy" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Skryť dočasné obrazy" + +#: src/Images.jsx:158 +msgid "History" +msgstr "" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Cesta na hostiteľovi" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Port na hostiteľovi" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Nápoveda k portu na hostiteľovi" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP adresa" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Nápoveda k IP adrese" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ignorovať staticky nastavené IP adresy" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ignorovať staticky nastavené MAC adresy" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Obraz" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "" + +#: src/ContainerCommitModal.jsx:35 +#, fuzzy +#| msgid "Container name" +msgid "Image name is required" +msgstr "Názov kontajneru" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Nápoveda k výberu obrazu" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Obrazy" + +#: src/ImageRunModal.jsx:940 +#, fuzzy +#| msgid "CPU shares" +msgid "Increase CPU shares" +msgstr "CPU podiely" + +#: src/ImageRunModal.jsx:1050 +#, fuzzy +#| msgid "Integration" +msgid "Increase interval" +msgstr "Integrácia" + +#: src/ImageRunModal.jsx:979 +#, fuzzy +#| msgid "Maximum retries" +msgid "Increase maximum retries" +msgstr "Maximum pokusov" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "" + +#: src/ImageRunModal.jsx:1100 +#, fuzzy +#| msgid "Start docker" +msgid "Increase start period" +msgstr "Spustiť docker" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integrácia" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +#, fuzzy +#| msgid "Integration" +msgid "Interval" +msgstr "Integrácia" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "" + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Kľúč" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "" + +#: src/ContainerDetails.jsx:71 +#, fuzzy +#| msgid "Checkpoint" +msgid "Latest checkpoint" +msgstr "Vytvoriť kontrolný bod" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +#, fuzzy +#| msgid "Loading logs..." +msgid "Loading details..." +msgstr "Načítanie záznamov udalostí..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Načítanie záznamov udalostí..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Načítanie..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Miestne" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Miestne obrazy" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Záznamy udalostí" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC adresa" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Maximum pokusov" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Pamäť" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Pamäťový limit" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Pamäťová jednotka" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Mód" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Názov" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "" + +#: src/ContainerRenameModal.jsx:68 +#, fuzzy +#| msgid "Container name" +msgid "New container name" +msgstr "Názov kontajneru" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Názov nového obrazu" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Nie" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Žiadne kontajnery" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Tento obraz nepoužívajú žiadne kontajnery" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "V tomto pode nie sú žiadne kontajnery" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Žiadne kontajneri nevyhovujú danému filtru" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Neboli definované žiadne premenné prostredia" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Žiadne obrazy" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Žiadne obrazy neboli nájdené" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Žiadne obrazy nevyhovujú danému filtru" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Žiaden výsledok pre $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Žiadne spustené kontajnery" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Žiadne špecifikované zväzky" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Pri chybe" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Iba bežiace" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Možnosti" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Vlastník" + +#: src/ImageRunModal.jsx:761 +#, fuzzy +#| msgid "Owner" +msgid "Owner help" +msgstr "Vlastník" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Pozastaviť" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Zastaviť kontajner keď sa vytvára obraz" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Pozastavený" + +#: src/PodCreateModal.jsx:89 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Pod failed to be created" +msgstr "Kontajner sa nepodarilo vytvoriť" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker kontajnery" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Služba Docker nie je aktívna" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Mapovanie portov" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Porty" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Súkromný" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokol" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Vyčistiť" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Vyčistiť nepoužívané kontajnery" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Vyčistiť nepoužívané obrazy" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +#, fuzzy +#| msgid "No running containers" +msgid "Pruning containers" +msgstr "Žiadne spustené kontajnery" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Prerezávanie obrazov" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Stiahnúť najnovší obraz" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Sťahuje sa" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Odstrániť položku" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Odstráni vybrané nespustené kontajnery" + +#: src/util.js:23 +msgid "Removing" +msgstr "Odstraňuje sa" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "" + +#: src/ContainerRenameModal.jsx:85 +#, fuzzy +#| msgid "Restore container $0" +msgid "Rename container $0" +msgstr "Obnovenie kontajneru $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Reštartovať" + +#: src/ImageRunModal.jsx:948 +#, fuzzy +#| msgid "Restart" +msgid "Restart policy" +msgstr "Reštartovať" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +#, fuzzy +#| msgid "Host path" +msgid "Restart policy help" +msgstr "Cesta na hostiteľovi" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "" + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Obnoviť" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Obnovenie kontajneru $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "" + +#: src/ImageSearchModal.jsx:190 +#, fuzzy +#| msgid "Please retry another term." +msgid "Retry another term." +msgstr "Skúste iný pojem." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Hľadať podľa mena alebo popisu" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Hľadanie obrazu" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Hľadá sa..." + +#: src/ImageRunModal.jsx:822 +#, fuzzy +#| msgid "Loading..." +msgid "Searching: $0" +msgstr "Načítanie..." + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Zdielaný" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Zobraziť obrazy" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "" + +#: src/ContainerIntegration.jsx:82 +#, fuzzy +#| msgid "Show images" +msgid "Show less" +msgstr "Zobraziť obrazy" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Zobraziť viac" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Veľkosť" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Spustiť" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +#, fuzzy +#| msgid "Start docker" +msgid "Start period" +msgstr "Spustiť docker" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Spustiť docker" + +#: src/ImageSearchModal.jsx:185 +#, fuzzy +#| msgid "Please start typing to look for images." +msgid "Start typing to look for images." +msgstr "Začnite písať na vyhľadanie obrazov." + +#: src/ContainerHealthLogs.jsx:105 +#, fuzzy +#| msgid "Start" +msgid "Started at" +msgstr "Spustiť" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Stav" + +#: src/ContainerHealthLogs.jsx:56 +#, fuzzy +#| msgid "State" +msgid "Status" +msgstr "Stav" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Zastaviť" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Zastavený" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Systém" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Systémový docker je tiež dostupný" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Tag" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Tagy" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "" + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "" + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Riešiť problém" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +#, fuzzy +#| msgid "Failed to download image $0:$1" +msgid "Unable to load image history" +msgstr "Nepodarilo sa stiahnuť obraz $0:$1" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Aktívny od $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Využívaný s" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Užívateľský docker je tiež dostupný" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Používateľ:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Hodnota" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Zväzky" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +#, fuzzy +#| msgid "Checkpoint" +msgid "When unhealthy" +msgstr "Vytvoriť kontrolný bod" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "S terminálom" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "" + +#: src/manifest.json:0 +msgid "container" +msgstr "kontajner" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "sťahuje sa" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "" + +#: src/manifest.json:0 +msgid "image" +msgstr "obraz" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "" + +#: src/ImageDeleteModal.jsx:79 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate" +msgstr "Skryť dočasné obrazy" + +#: src/ImageDeleteModal.jsx:59 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate image" +msgstr "Skryť dočasné obrazy" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "Nedostupné" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "nedostupné" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +#, fuzzy +#| msgid "Ports" +msgid "ports" +msgstr "Porty" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "systém" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "nepoužitý" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "používateľ:" + +#: src/Containers.jsx:547 +#, fuzzy +#| msgid "Volumes" +msgid "volumes" +msgstr "Zväzky" + +#~ msgid "Delete $0" +#~ msgstr "Odstrániť $0" + +#, fuzzy +#~| msgid "Restart" +#~ msgid "Restarting" +#~ msgstr "Reštartovať" + +#, fuzzy +#~| msgid "Please confirm deletion of $0" +#~ msgid "Confirm deletion of $0" +#~ msgstr "Potvrďte zmazanie $0" + +#, fuzzy +#~| msgid "Please confirm deletion of pod $0" +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Potvrďte zmazanie podu $0" + +#, fuzzy +#~| msgid "Please confirm force deletion of pod $0" +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Potvrďte vynútené zmazanie podu $0" + +#, fuzzy +#~| msgid "Please confirm forced deletion of $0" +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Potvrďte nútené zmazanie $0" + +#~ msgid "Container is currently running." +#~ msgstr "Kontajner momentálne beží." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Do exportu nezahŕnať zmeny v koreňovom súborovovom systéme" + +#, fuzzy +#~| msgid "Delete tagged images" +#~ msgid "Delete unused $0 images:" +#~ msgstr "Zmazať označené obrazy" + +#~ msgid "created" +#~ msgstr "vytvorený" + +#~ msgid "exited" +#~ msgstr "skončený" + +#~ msgid "paused" +#~ msgstr "pozastavený" + +#, fuzzy +#~| msgid "user" +#~ msgid "user" +#~ msgstr "používateľ" + +#~ msgid "Commit image" +#~ msgstr "Vytvoriť obraz" + +#~ msgid "Format" +#~ msgstr "Formát" + +#~ msgid "Message" +#~ msgstr "Správa" + +#~ msgid "Pause the container" +#~ msgstr "Pozastaviť kontajner" + +#~ msgid "Add item" +#~ msgstr "Pridať položku" + +#, fuzzy +#~| msgid "Host port" +#~ msgid "Host port (optional)" +#~ msgstr "Port na hostiteľovi" + +#~ msgid "IP prefix length" +#~ msgstr "Dĺžka predpony IP adresy" + +#~ msgid "Run" +#~ msgstr "Spustiť" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Ste si istý/istá, že chcete odstrániť tento obraz?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Nepodarilo sa pripojiť k tomuto kontajneru: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Nepodarilo sa otvoriť kanál: $0" + +#~ msgid "Everything" +#~ msgstr "Všetko" + +#~ msgid "Security" +#~ msgstr "Bezpečnosť" diff --git a/ui/cockpit-docker/po/sv.po b/ui/cockpit-docker/po/sv.po new file mode 100644 index 0000000..7bf540f --- /dev/null +++ b/ui/cockpit-docker/po/sv.po @@ -0,0 +1,1484 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Gleb Vassiljev , 2020. +# Göran Uddeborg , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-11-29 13:31+0000\n" +"Last-Translator: Luna Jernberg \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 5.2.1\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 behållare" +msgstr[1] "$0 behållare" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 avbild, total, $1" +msgstr[1] "$0 avbilder, totalt, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 sekund" +msgstr[1] "$0 sekunder" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 oanvänd avbild, $1" +msgstr[1] "$0 oanvända avbilder, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 till 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "Åtgärd att ta när behållaren övergår till ett ohälsosamt tillstånd." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Lägg till portmappning" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Lägg till variabel" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Lägg till volym" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Alla" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Alla register" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Alltid" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Ett fel uppstod" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Upphovsman" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Kör igång docker automatiskt vid uppstart" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU-andelar hjälp" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU-andelar" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU-andelar avgör prioriteten på körande behållare. Standardprioriteten är " +"1024. Ett högre tal prioriterar denna behållare. Ett lägre tal sänker " +"prioriteten." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Avbryt" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Kontrollerar hälsa" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Checkpunkt" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "checkpunkt och återställnings stöd" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Ta checkpunkt på behållare $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Klicka för att se publicerade portar" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Klicka för att se volymer" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Cockpit komponent för Docker-behållare" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Kommando" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Kommentarer" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Fastställ" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Commit behållare" + +#: src/util.js:23 +msgid "Configured" +msgstr "Konfigurerad" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konsol" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Behållare" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Behållaren misslyckades att skapas" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Behållaren misslyckades att startas" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Behållaren kör inte" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Behållarnamn" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Behållarnamn krävs." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Behållarsökväg" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "Behållarens sökväg får inte vara tom" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Behållarport" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "Behållarporten får inte vara tom" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Behållare" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Skapa" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Skapa en ny avbild baserad på det aktuella läget för $0 behållaren." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Skapa och kör" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Skapa behållare" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Skapa behållare i $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Skapa behållare i kapsel" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Skapa pod" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Skapad" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Skapad av" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Minska CPU-andelar" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Minska intervallet" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Minska maximalt antal försök igen" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Minska minne" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Minska återförsök" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Minska startintervallet" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Minska timeout" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Radera" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "Radera $0 avbild?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Radera $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Radera avbild" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Radera podd $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Radera taggade avbilder" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Ta bort oanvända systemavbilder:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Ta bort oanvända användaravbilder:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "När en behållare raderas försvinner även all data i den." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "När en behållare som körs raderas försvinner även all data i den." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Att ta bort denna kapsel kommer ta bort följande behållare:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Detaljer" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Disk utrymme" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Docker-format är användbart när du delar avbilden med Docker eller Moby " +"Engine" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Ladda ner" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Ladda ner ny avbild" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Tom podd $0 kommer att tas bort permanent." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Ingångspunkt" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Miljövariabler" + +#: src/util.js:26 +msgid "Error" +msgstr "Fel" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Felmeddelande" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Ett fel uppstod vid anslutning till konsolen" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Exempel, Ditt Namn " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Exempel: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Avslutats" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Misslyckad hälsokörning" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Kunde inte ta checkpunkt av behållare $0" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Misslyckades med att rensa upp behållaren" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Kunde inte fastställa behållaren $0" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Misslyckades att skapa behållaren $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Kunde inte ladda ner avbild $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Misslyckades att tvingande ta bort behållare $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Misslyckades att tvingande ta bort avbilden $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Misslyckades med tvingad omstart av kapseln $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Misslyckades att tvinga stopp av kapsel $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Misslyckades med att pausa behållaren $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Misslyckades att pausa kapseln $0" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Misslyckades att rensa oanvända behållare" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Misslyckades att rensa oanvända avbilder" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Misslyckades med att hämta avbilden $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Misslyckades att ta bort behållaren $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Misslyckades att ta bort avbilden $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Misslyckades att byta namn på behållaren $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Misslyckades att starta om behållaren $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Misslyckades att starta om kapseln $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Misslyckades att återställa behållaren $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Misslyckades att återuppta behållaren $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Misslyckades att återuppta kapseln $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Misslyckades att köra behållaren $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Misslyckades att köra hälsokontrollen på behållare $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Misslyckades att söka efter avbilder." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Misslyckades att söka efter avbilder: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Misslyckades att söka efter nya avbilder" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Misslyckades att starta behållaren $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Misslyckades att starta kapseln $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Misslyckades att stoppa behållaren $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Misslyckades att stoppa kapseln $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Misslyckanden i följd" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Framtvinga commit" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Framtvinga borttagande" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Framtvinga borttagande av podd $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Framtvinga omstart" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Framtvinga stopp" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Gateway" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Hälsokontroll" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Hälsokontrollens intervallhjälp" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Hälsokontrollens återförsökshjälp" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Hälsokontrollens startintervallshjälp" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Hälsokontrollens tidsgränshjälp" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Hälsokontrollens checkåtgärd hjälp" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Hälsosam" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Dölj avbilder" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Dölj mellanliggande avbilder" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Historik" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Värdsökväg" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Värdport" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Värdport hjälp" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP-adress" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "IP-adress hjälp" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Ideal för utveckling" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Ideal för att köra tjänster" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Om värd-IP är inställd på 0.0.0.0 eller inte alls, kommer porten att bindas " +"till alla IP-adresser på värden." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Om värdporten inte är inställd kommer behållareporten att slumpmässigt " +"tilldelas en port på värden." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ignorera IP-adressen om den är statiskt satt" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ignorera MAC-adressen om den är statiskt satt" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Avbild" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Avbildsnamn är inte unikt" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Avbildsnamn krävs" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Avbildsval hjälp" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Avbilder" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Öka CPU-andelar" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Öka intervallet" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Öka maximalt antal försök igen" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Öka minne" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Öka återförsöken" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Öka startintervallet" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Öka timeout" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Integration" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Intervall" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Intervallet hur ofta hälsokontroller körs." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Ogiltiga tecken. Namn kan bara innehålla bokstäver, siffror och vissa " +"skiljetecken (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Behåll alla tillfälliga checkpunktsfiler" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Nyckel" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "Nyckel får inte vara tom" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Senaste 5 körningarna" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Senaste checkpunkt" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Låt fortsätta köra efter att skriva checkpunkt till disk" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Läser in detaljer …" + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Läser in loggar …" + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Läser in …" + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Lokal" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Lokala avbilder" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Loggar" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC-adress" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Maximalt antal försök igen" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Minne" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Minnesgräns" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Minnesenhet" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Läge" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Flera taggar finns för denna avbild. Välj vilka taggade avbilder som skall " +"raderas." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "Måste vara en giltig IP adress" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Namn" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Namn används redan" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Nytt behållarnamn" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Nytt Avbildsnamn" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Nej" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Ingen åtgärd" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Inga behållare" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Inga behållare använder denna avbild" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Inga behållare i denna kapsel" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Inga behållare som stämmer med det aktuella filtret" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Inga miljövariabler specificerade" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Inga avbilder" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Inga avbilder funna" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Inga avbilder som stämmer med det aktuella filtret" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Ingen Etikett" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Inga portar exponerade" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Inga resultat för $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Inga körande behållare" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Inga volymer specificerade" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Vid misslyckande" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Endast körande" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Alternativ" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Ägare" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Ägare hjälp" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Lyckad hälsokontrollskörning" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Klistra in en eller flera rader med nyckel=värdepar i valfritt fält för " +"massimport" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Pausa" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Pausa behållaren när du skapar en avbild" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Pausad" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Podden kunde inte skapas" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Pod namn" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker-behållare" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker-tjänsten är inte aktiv" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Portkartering" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Portar" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Portar under 1024 kan inte mappas" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Privat" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokoll" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Rensa" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Rensa oanvända behållare" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Rensa oanvända avbilder" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Rensar behållare" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Rensar avbilder" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Hämta senaste avbild" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Hämtar" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Skrivskyddad åtkomst" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Läs och skrivåtkomst" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Ta bort post" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Tar bort valda icke-körande behållare" + +#: src/util.js:23 +msgid "Removing" +msgstr "Tar bort" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Byt namn" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Byt namn på behållaren $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Resursgränser kan ställas in" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Starta om" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Starta om policy" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Starta om policy hjälp" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Starta om policy att följa när behållare avslutas." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Starta om policyn till att följa när behållare avslutar. Att använda " +"fortlevande (linger) för automatstartande behållare fungerar kanske inte i " +"vissa situationer, som när ecryptfs, systemd-homed, NFS eller 2FA används " +"för ett användarkonto." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Återställ" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Återställ behållaren $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Återställ med etablerade TCP-förbindelser" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Begränsat av användarkontobehörigheter" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Återuppta" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Omförsök" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Försök igen med en annan term." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Kör hälsokontroll" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Kör" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Sök efter namn eller beskrivning" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Sök efter register" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Sök efter" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Sök efter en avbild" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Söksträng eller behållareplats" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Söker …" + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Söker: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Delad" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Visa" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Visa avbilder" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Visa mellanliggande avbilder" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Visa mindre" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Visa mer" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Storlek" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Starta" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Startperiod" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Starta docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Börja skriva för att leta efter avbilder." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Startad vid" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Tillstånd" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Status" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Stoppa" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Stoppad" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Stöd att bevara etablerade TCP-förbindelser" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "System" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "System-docker-tjänsten är också tillgänglig" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Tagg" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Taggar" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Cockpit-användargränssnittet för Docker-behållare." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Initieringstiden sombehövs för att en behållare skall komma igång." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Den maximala tiden som tillåts för att klara av hälsokontrollen före ett " +"intervall betraktas som misslyckat." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Antalet återförsök som tillåts före en hälsokontroll betraktas som ohälsosam." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Tidsgräns" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Felsök" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Skriv för att filtrera …" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Kunde inte ladda avbildshistoriken" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Ohälsosam" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Uppe sedan $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Använd gammalt Docker-format" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Används av" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Användare" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Användar-docker-tjänsten är också tillgänglig" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Användare:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Värde" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Volymer" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "När ohälsosam" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Med terminal" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Skrivbar" + +#: src/manifest.json:0 +msgid "container" +msgstr "behållare" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "hämtar" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "värd[:port]/[användare]/behållare[:tagg]" + +#: src/manifest.json:0 +msgid "image" +msgstr "avbild" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "i" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "mellanliggande" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "mellanliggande avbild" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "ej tillämpligt" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "inte tillgängligt" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "kapselgrupp" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "portar" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "sekunder" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "system" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "oanvänd" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "användare:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "volymer" + +#~ msgid "Delete $0" +#~ msgstr "Radera $0" + +#~ msgid "select all" +#~ msgstr "välj alla" + +#~ msgid "Failure action" +#~ msgstr "Misslyckad åtgärd" + +#~ msgid "Restarting" +#~ msgstr "Startar om" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Bekräfta borttagning av $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Bekräfta borttagning av kapsel $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Bekräfta tvångsradering av kapsel $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Bekräfta tvångsradering av $0" + +#~ msgid "Container is currently running." +#~ msgstr "Behållaren kör för närvarande." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Inkludera inte rotfilsystemsändringar vid export" + +#~ msgid "Default with single selectable" +#~ msgstr "Standard med enkel valbar" + +#~ msgid "Start after creation" +#~ msgstr "Starta efter skapande" + +#, fuzzy +#~| msgid "Delete tagged images" +#~ msgid "Delete unused $0 images:" +#~ msgstr "Radera taggade avbilder" + +#~ msgid "created" +#~ msgstr "skapad" + +#~ msgid "exited" +#~ msgstr "avslutad" + +#~ msgid "paused" +#~ msgstr "pausad" + +#~ msgid "running" +#~ msgstr "kör" + +#~ msgid "stopped" +#~ msgstr "stoppad" + +#~ msgid "user" +#~ msgstr "användare" + +#~ msgid "Add on build variable" +#~ msgstr "Lägg till byggvariabel" + +#~ msgid "Commit image" +#~ msgstr "Fastställningsavbild" + +#~ msgid "Format" +#~ msgstr "Format" + +#~ msgid "Message" +#~ msgstr "Meddelande" + +#~ msgid "Pause the container" +#~ msgstr "Pausa behållaren" + +#~ msgid "Remove on build variable" +#~ msgstr "Ta bort byggvariabel" + +#~ msgid "Set container on build variables" +#~ msgstr "Sätt behållare på byggvariabler" + +#~ msgid "Add item" +#~ msgstr "Lägg till post" + +#~ msgid "Host port (optional)" +#~ msgstr "Värdport (valfri)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (valfri)" + +#~ msgid "ReadOnly" +#~ msgstr "LäsEndast" + +#~ msgid "IP prefix length" +#~ msgstr "IP-prefixlängd" + +#~ msgid "Get new image" +#~ msgstr "Hämta ny avbild" + +#~ msgid "Run" +#~ msgstr "Kör" + +#~ msgid "On build" +#~ msgstr "Vid bygge" + +#~ msgid "Everything" +#~ msgstr "Allting" diff --git a/ui/cockpit-docker/po/tr.po b/ui/cockpit-docker/po/tr.po new file mode 100644 index 0000000..5d77909 --- /dev/null +++ b/ui/cockpit-docker/po/tr.po @@ -0,0 +1,1501 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Oğuz Ersen , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-12-01 18:43+0000\n" +"Last-Translator: Weblate Translation Memory \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1\n" +"X-Generator: Weblate 5.2.1\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 kapsayıcı" +msgstr[1] "$0 kapsayıcı" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "Toplam $0 kalıp, $1" +msgstr[1] "Toplam $0 kalıp, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 saniye" +msgstr[1] "$0 saniye" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 kullanılmayan kalıp, $1" +msgstr[1] "$0 kullanılmayan kalıp, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1'den 65535'e" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "" +"Kapsayıcı sağlıksız bir duruma geçtikten sonra gerçekleştirilecek eylem." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Bağlantı noktası eşlemesi ekle" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Değişken ekle" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Birim ekle" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Tümü" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Tüm kayıtlar" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Her zaman" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Bir hata meydana geldi" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Hazırlayan" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Docker'ı önyüklemede otomatik olarak başlat" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU Paylaşımları yardımı" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU paylaşımları" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU paylaşımları, kapsayıcıları çalıştırmanın önceliğini belirler. " +"Varsayılan öncelik 1024'dür. Daha yüksek bir sayı bu kapsayıcıya öncelik " +"verir. Daha düşük bir sayı önceliği azaltır." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "İptal" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Sağlık denetleniyor" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Denetim noktası" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Denetim noktası ve geri yükleme desteği" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "$0 kapsayıcısı denetim noktası" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Yayınlanan bağlantı noktalarını görmek için tıklayın" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Birimleri görmek için tıklayın" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Docker kapsayıcıları için Cockpit bileşeni" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Komut" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Açıklamalar" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "İşle" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Kapsayıcı işle" + +#: src/util.js:23 +msgid "Configured" +msgstr "Yapılandırıldı" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Konsol" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Kapsayıcı" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Kapsayıcının oluşturulması başarısız oldu" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Kapsayıcının başlatılması başarısız oldu" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Kapsayıcı çalışmıyor" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Kapsayıcı adı" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Kapsayıcı adı gerekli." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Kapsayıcı yolu" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "Kapsayıcı yolu boş olmamak zorundadır" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Kapsayıcı bağlantı noktası" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "Kapsayıcı bağlantı noktası boş olmamak zorundadır" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Kapsayıcılar" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Oluştur" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "$0 kapsayıcısının şu anki durumuna göre yeni bir kalıp oluşturun." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Oluştur ve çalıştır" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Kapsayıcı oluştur" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "$0 içinde kapsayıcı oluştur" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Bölme içinde kapsayıcı oluştur" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Bölme oluştur" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Oluşturuldu" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Oluşturan" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "CPU paylaşımlarını azalt" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Aralığı azalt" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "En fazla yeniden denemeyi azalt" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Belleği azalt" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Yeniden denemeleri azalt" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Başlangıç süresini azalt" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Zaman aşımını azalt" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Sil" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "$0 kalıbı silinsin mi?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "$0 silinsin mi?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "Kalıbı sil" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "$0 bölmesi silinsin mi?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Etiketli kalıpları sil" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Kullanılmayan sistem kalıplarını sil:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Kullanılmayan kullanıcı kalıplarını sil:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "Bir kapsayıcıyı silmek içindeki tüm verileri silecek." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "Çalışan bir kapsayıcıyı silmek içindeki tüm verileri silecek." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Bu bölmeyi silmek aşağıdaki kapsayıcıları kaldıracak:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Ayrıntılar" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Disk alanı" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Docker biçimi, kalıbı Docker veya Moby Engine ile paylaşırken kullanışlıdır" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "İndir" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Yeni kalıbı indir" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Boş bölme $0 kalıcı olarak kaldırılacaktır." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Giriş noktası" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Ortam değişkenleri" + +#: src/util.js:26 +msgid "Error" +msgstr "Hata" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Hata iletisi" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Konsola bağlanırken hata meydana geldi" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Örnek, Adınız " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Örnek: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Çıkıldı" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Sağlık işlemini çalıştırma başarısız oldu" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "$0 kapsayıcısını denetleme noktası başarısız oldu" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Kapsayıcıyı temizleme başarısız oldu" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "$0 kapsayıcısını işleme başarısız oldu" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "$0 kapsayıcısını oluşturma başarısız oldu" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "$0:$1 kalıbını indirme başarısız oldu" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "$0 kapsayıcısını zorla kaldırma başarısız oldu" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "$0 kalıbını zorla kaldırma başarısız oldu" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "$0 bölmesini yeniden başlatmaya zorlama başarısız oldu" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "$0 bölmesini zorla durdurma başarısız oldu" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "$0 kapsayıcısını duraklatma başarısız oldu" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "$0 bölmesini duraklatma başarısız oldu" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Kullanılmayan kapsayıcıları ayıklama başarısız oldu" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Kullanılmayan kalıpları ayıklama başarısız oldu" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "$0 kalıbını çekme başarısız oldu" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "$0 kapsayıcısını kaldırma başarısız oldu" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "$0 kalıbını kaldırma başarısız oldu" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "$0 kapsayıcısını yeniden adlandırma başarısız oldu" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "$0 kapsayıcısını yeniden başlatma başarısız oldu" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "$0 bölmesini yeniden başlatma başarısız oldu" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "$0 kapsayıcısını geri yükleme başarısız oldu" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "$0 kapsayıcısını sürdürme başarısız oldu" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "$0 bölmesini sürdürme başarısız oldu" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "$0 kapsayıcısını çalıştırma başarısız oldu" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "$0 kapsayıcısında sağlık denetimi çalıştırma başarısız oldu" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Kalıpları arama başarısız oldu." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Kalıpları arama başarısız oldu: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Yeni kalıpları arama başarısız oldu" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "$0 kapsayıcısını başlatma başarısız oldu" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "$0 bölmesini başlatma başarısız oldu" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "$0 kapsayıcısını durdurma başarısız oldu" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "$0 bölmesini durdurma başarısız oldu" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Başarısız olan seri" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "İşlemeye zorla" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Silmeye zorla" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "$0 bölmesi silmeye zorlansın mı?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Yeniden başlatmaya zorla" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Durdurmaya zorla" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Ağ geçidi" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Sağlık denetimi" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Sağlık denetimi aralığı yardımı" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Sağlık denetimi yeniden denemeleri yardımı" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Sağlık denetimi başlangıç dönemi yardımı" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Sağlık denetimi zaman aşımı yardımı" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Sağlık denetimi hatası eylem yardımı" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Sağlıklı" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Kalıpları gizle" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Ara kalıpları gizle" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Geçmiş" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Anamakine yolu" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Anamakine bağlantı noktası" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Anamakine b.noktası yardım" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "Kimlik" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP adresi" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "IP adresi yardım" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Geliştirme için ideal" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Çalışan hizmetler için ideal" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Eğer anamakine IP'si 0.0.0.0 olarak ayarlanırsa veya hiç ayarlanmazsa, " +"bağlantı noktası anamakinedeki tüm IP'lere bağlanır." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Eğer anamakine bağlantı noktası ayarlanmazsa, kapsayıcı bağlantı noktası " +"anamakinede rastgele bir bağlantı noktasına atanacaktır." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Sabit olarak ayarlanmışsa IP adresini yoksay" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Sabit olarak ayarlanmışsa MAC adresini yoksay" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Kalıp" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Kalıp adı benzersiz değil" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Kalıp adı gerekli" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Kalıp seçim yardımı" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Kalıplar" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "CPU paylaşımlarını artır" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Aralığı artır" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "En fazla yeniden denemeyi artır" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Belleği artır" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Yeniden denemeleri artır" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Başlangıç süresini artır" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Zaman aşımını artır" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Bütünleştirme" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Aralık" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Sağlık denetiminin ne sıklıkta çalıştırıldığı aralığı." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Geçersiz karakterler. Ad sadece harf, sayı ve belirli noktalama işaretlerini " +"(_ . -) içerebilir." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Tüm geçici denetim noktası dosyalarını sakla" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Anahtar" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "Anahtar boş olmamak zorundadır" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Son 5 çalıştırma" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Son denetim noktası" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Denetim noktasını diske yazdıktan sonra çalışır durumda bırak" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Ayrıntılar yükleniyor..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Günlükler yükleniyor..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Yükleniyor..." + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Yerel" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Yerel kalıplar" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Günlükler" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC adresi" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "En fazla yeniden deneme" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Bellek" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Bellek sınırı" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Bellek birimi" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Mod" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Bu kalıp için birden fazla etiket var. Silinecek etiketlenmiş kalıpları " +"seçin." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "Geçerli bir IP adresi olmak zorundadır" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Ad" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "Ad zaten kullanımda" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Yeni kapsayıcı adı" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Yeni kalıp adı" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Hayır" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Eylem yok" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Kapsayıcılar yok" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Bu kalıbı hiçbir kapsayıcı kullanmıyor" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "Bu bölmede kapsayıcılar yok" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Şu anki süzgeçle eşleşen kapsayıcılar yok" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Belirtilen ortam değişkenleri yok" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Kalıplar yok" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Bulunan kalıplar yok" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Şu anki süzgeçle eşleşen kalıplar yok" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Etiket yok" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Açığa çıkan bağlantı noktaları yok" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "$0 için sonuçlar yok" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Çalışan kapsayıcılar yok" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Belirtilen birimler yok" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "Başarısızlıkla" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Sadece çalışanlar" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Seçenekler" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Sahibi" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Sahibi yardımı" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Sağlık çalıştırması geçti" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Toplu içe aktarma için herhangi bir alana bir veya daha fazla anahtar=değer " +"çifti satırı yapıştırın" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Duraklat" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Kalıp oluştururken kapsayıcıyı duraklatın" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Duraklatıldı" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Bölmenin oluşturulması başarısız oldu" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Bölme adı" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker kapsayıcıları" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker hizmeti etkin değil" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Bağlantı noktası eşleme" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Bağlantı noktaları" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "1024 altındaki bağlantı noktaları eşlenebilir" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Özel" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Protokol" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Ayıkla" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Kullanılmayan kapsayıcıları ayıkla" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Kullanılmayan kalıpları ayıkla" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Kapsayıcılar ayıklanıyor" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Kalıplar ayıklanıyor" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Son kalıbı çek" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Çekiliyor" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Salt-okunur erişim" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Okuma-yazma erişimi" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Öğeyi kaldır" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Seçilen çalışmayan kapsayıcıları kaldırır" + +#: src/util.js:23 +msgid "Removing" +msgstr "Kaldırılıyor" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Yeniden adlandır" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "$0 kapsayıcısını yeniden adlandır" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Kaynak sınırları ayarlanabilir" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Yeniden başlat" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Yeniden başlatma ilkesi" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Yeniden başlatma ilkesi yardımı" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Kapsayıcılardan çıkıldığında izlenecek ilkeyi yeniden başlatın." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Kapsayıcılar çıktığında izlenecek ilkeyi yeniden başlatın. Otomatik başlatma " +"kapsayıcıları için geciktirme kullanılması, bir kullanıcı hesabında " +"ecryptfs, systemd-homed, NFS veya 2FA kullanıldığında olduğu gibi bazı " +"durumlarda çalışmayabilir." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Geri yükle" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "$0 kapsayıcısını geri yükle" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Kurulu TCP bağlantıları ile geri yükle" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Kullanıcı hesabı izinleri tarafından kısıtlanmış" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Sürdür" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Yeniden denemeler" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Başka bir terimi yeniden deneyin." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Sağlık denetimini çalıştır" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Çalışıyor" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Ada veya açıklamaya göre ara" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Kayıt defterine göre ara" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Ara" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Kalıp ara" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Arama dizgisi veya kapsayıcı konumu" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Aranıyor..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Aranan: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Paylaşılan" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Göster" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Kalıpları göster" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Ara kalıpları göster" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Daha az göster" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Daha fazlasını göster" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Boyut" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Başlat" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Başlangıç süresi" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Docker'ı başlat" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Kalıpları aramak için yazmaya başlayın." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Başlama zamanı" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Durum" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Durum" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Durdur" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Durduruldu" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Kurulu TCP bağlantılarını korumayı destekle" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Sistem" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Sistem Docker hizmeti de kullanılabilir" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Etiket" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Etiketler" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Docker kapsayıcıları için Cockpit kullanıcı arayüzü." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Bir kapsayıcının önyükleme yapması için gereken başlatma süresi." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Bir aralığın başarısız olduğu kabul edilmeden önce sağlık denetimini " +"tamamlanması için izin verilen en fazla süre." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Bir sağlık denetiminden önce izin verilen yeniden deneme sayısı sağlıksız " +"olarak kabul edilir." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Zaman aşımı" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Sorun Giderme" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Süzmek için yazın…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Kalıp geçmişini yükleme başarısız oldu" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Sağlıksız" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "$0'dan beri aktif" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Eski Docker biçimini kullan" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Kullanan" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Kullanıcı" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Kullanıcı Docker hizmeti de kullanılabilir" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Kullanıcı:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Değer" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Birimler" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Sağlıksız olduğunda" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "Terminal ile" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Yazılabilir" + +#: src/manifest.json:0 +msgid "container" +msgstr "kapsayıcı" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "indiriliyor" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "anamakine[:b.noktası]/[kullanıcı]/kapsayıcı[:etiket]" + +#: src/manifest.json:0 +msgid "image" +msgstr "kalıp" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "şurada" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "orta seviye" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "orta seviye kalıp" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "yok" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "kullanılabilir değil" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "bölme grubu" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "bağlantı noktaları" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "saniye" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "sistem" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "kullanılmayan" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "kullanıcı:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "birimler" + +#~ msgid "Delete $0" +#~ msgstr "$0 sil" + +#~ msgid "select all" +#~ msgstr "tümünü seç" + +#~ msgid "Failure action" +#~ msgstr "Başarısız eylem" + +#~ msgid "Restarting" +#~ msgstr "Yeniden başlatılıyor" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "$0 için silme işlemini onaylayın" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "$0 bölmesinin silme işlemini onaylayın" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "$0 bölmesinin zorla silme işlemini onaylayın" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "$0 için zorla silme işlemini onaylayın" + +#~ msgid "Container is currently running." +#~ msgstr "Kapsayıcı şu anda çalışıyor." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Dışa aktarırken kök dosya sistemi değişikliklerini dahil etme" + +#~ msgid "Default with single selectable" +#~ msgstr "Tek seçilebilir ile varsayılan" + +#~ msgid "Start after creation" +#~ msgstr "Oluşturmadan sonra başlat" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Kullanılmayan $0 kalıplarını sil:" + +#~ msgid "created" +#~ msgstr "oluşturuldu" + +#~ msgid "exited" +#~ msgstr "çıkıldı" + +#~ msgid "paused" +#~ msgstr "duraklatıldı" + +#~ msgid "running" +#~ msgstr "çalışıyor" + +#~ msgid "stopped" +#~ msgstr "durduruldu" + +#~ msgid "user" +#~ msgstr "kullanıcı" + +#~ msgid "Add on build variable" +#~ msgstr "Yapım değişkeninde ekle" + +#~ msgid "Commit image" +#~ msgstr "Kalıbı işle" + +#~ msgid "Format" +#~ msgstr "Biçim" + +#~ msgid "Message" +#~ msgstr "İleti" + +#~ msgid "Pause the container" +#~ msgstr "Konteyneri duraklat" + +#~ msgid "Remove on build variable" +#~ msgstr "Yapım değişkeninde kaldır" + +#~ msgid "Set container on build variables" +#~ msgstr "Yapım değişkenlerinde kapsayıcıyı ayarla" + +#~ msgid "Add item" +#~ msgstr "Öğe ekle" + +#~ msgid "Host port (optional)" +#~ msgstr "Anamakine bağlantı noktası (isteğe bağlı)" + +#~ msgid "IP (optional)" +#~ msgstr "IP (isteğe bağlı)" + +#~ msgid "ReadOnly" +#~ msgstr "SadeceOku" + +#~ msgid "IP prefix length" +#~ msgstr "IP ön ek uzunluğu" + +#~ msgid "Get new image" +#~ msgstr "Yeni kalıp al" + +#~ msgid "Run" +#~ msgstr "Çalıştır" + +#~ msgid "On build" +#~ msgstr "Yapım anında" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Bu kalıbı silmek istediğinizden emin misiniz?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Bu konteynere iliştirilemedi: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Kanal açılamadı: $0" + +#~ msgid "Everything" +#~ msgstr "Her şey" + +#~ msgid "Security" +#~ msgstr "Güvenlik" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "$time ($type) taraması hiçbir güvenlik açığı bulamadı." + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "Web Konsolu'nun bu sürümü bir terminali desteklememektedir." diff --git a/ui/cockpit-docker/po/uk.po b/ui/cockpit-docker/po/uk.po new file mode 100644 index 0000000..7bb2894 --- /dev/null +++ b/ui/cockpit-docker/po/uk.po @@ -0,0 +1,1522 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Yuri Chornoivan , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-08-07 10:58+0000\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.18.2\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0 контейнер" +msgstr[1] "$0 контейнери" +msgstr[2] "$0 контейнерів" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "$0 образ загалом, $1" +msgstr[1] "$0 образи загалом, $1" +msgstr[2] "$0 образів загалом, $1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 секунда" +msgstr[1] "$0 секунди" +msgstr[2] "$0 секунд" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0 невикористаний образ, $1" +msgstr[1] "$0 невикористані образи, $1" +msgstr[2] "$0 невикористаних образів, $1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "Дія, яку слід виконати після переходу контейнера у небезпечний стан." + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "Додати прив'язку портів" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "Додати змінну" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "Додати том" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "Усі" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "Усі реєстри" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "Завжди" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "Сталася помилка" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "Автор" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "Автоматично запускати docker під час завантаження" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "Процесор" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "Довідка щодо спільних процесорів" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "Спільне використання процесора" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"Спільні процесори визначають пріоритетність запуску контейнерів. Типовою " +"пріоритетністю є 1024. Більші числа роблять контейнер пріоритетнішим. Менші " +"числа зменшують пріоритетність." + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "Скасувати" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "Перевіряємо працездатність" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "Контрольна точка" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "Підтримка контрольних точок і відновлення" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "Контрольна точка контейнера $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "Натисніть, щоб переглянути оприлюднені порти" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "Натисніть, щоб переглянути томи" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Компонент Cockpit для контейнерів Docker" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "Команда" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "Коментарі" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "Надіслати" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "Внести контейнер" + +#: src/util.js:23 +msgid "Configured" +msgstr "Налаштовано" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "Консоль" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "Контейнер" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "Не вдалося створити контейнер" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "Не вдалося запустити контейнер" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "Контейнер не запущено" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "Назва контейнера" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "Слід вказати назву контейнера." + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "Шлях до контейнера" + +#: src/Volume.jsx:23 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container path must not be empty" +msgstr "Не вдалося створити контейнер" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "Порт контейнера" + +#: src/PublishPort.jsx:37 +#, fuzzy +#| msgid "Container failed to be created" +msgid "Container port must not be empty" +msgstr "Не вдалося створити контейнер" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "Контейнери" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "Створити" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "Створити образ на основі поточного стану контейнера $0." + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "Створити і запустити" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "Створити контейнер" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "Створити контейнер у $0" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "Створити контейнер у стручку" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "Створити стручок" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "Створено" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "Створено" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "Зменшити спільне використання процесора" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "Зменшити інтервал" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "Зменшити максимум повторних спроб" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "Зменшити пам'ять" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "Зменшити кількість повторних спроб" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "Зменшити період запуску" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "Зменшити час очікування" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "Вилучити" + +#: src/ImageDeleteModal.jsx:92 +#, fuzzy +#| msgid "Delete $0?" +msgid "Delete $0 image?" +msgstr "Вилучити $0?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "Вилучити $0?" + +#: src/ImageDeleteModal.jsx:96 +#, fuzzy +#| msgid "Delete tagged images" +msgid "Delete image" +msgstr "Вилучити позначені міткою образи" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "Вилучити кокон $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "Вилучити позначені міткою образи" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "Вилучити невикористані образи системи:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "Вилучити невикористані образи користувача:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "" +"Вилучення контейнера призведе до витирання усіх даних, що на ньому " +"зберігаються." + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "" +"Вилучення запущеного контейнера призведе до витирання усіх даних, що на " +"ньому зберігаються." + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "Вилучення цього кокону призведе до вилучення таких контейнерів:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "Подробиці" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "Місце на диску" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "" +"Формат Docker корисний, якщо ви захочете використовувати образ спільно у " +"середовищах Docker або Moby Engine" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "Отримати" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "Отримати новий образ" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "Порожній кокон $0 буде остаточно вилучено." + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "Точка входження" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "Змінні середовища" + +#: src/util.js:26 +msgid "Error" +msgstr "Помилка" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "Повідомлення про помилку" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "Під час спроби встановити з'єднання з консоллю сталася помилка" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "Приклад: Ваше Ім'я " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "Приклад: $0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "Вийшов" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "Не вдалося запустити перевірку працездатності" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "Не вдалося створити контрольну точку контейнера $0" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "Не вдалося очистити контейнер" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "Не вдалося надіслати на обробку контейнер $0" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "Не вдалося створити контейнер $0" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "Не вдалося отримати образ $0:$1" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "Не вдалося примусово вилучити контейнер $0" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "Не вдалося примусово вилучити образ $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "Не вдалося примусово перезапустити кокон $0" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "Не вдалося примусово зупинити кокон $0" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "Не вдалося призупинити роботу контейнера $0" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "Не вдалося призупинити кокон $0" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "Не вдалося позбутися невикористаних контейнерів" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "Не вдалося позбутися невикористаних образів" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "Не вдалося отримати образ $0" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "Не вдалося вилучити контейнер $0" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "Не вдалося вилучити образ $0" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "Не вдалося перейменувати контейнер $0" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "Не вдалося перезапустити контейнер $0" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "Не вдалося перезапустити кокон $0" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "Не вдалося відновити контейнер $0" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "Не вдалося відновити роботу контейнера $0" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "Не вдалося відновити кокон $0" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "Не вдалося запустити контейнер $0" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "Не вдалося запустити перевірку працездатності контейнера $0" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "Не вдалося виконати пошук образів." + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "Не вдалося виконати пошук образів: $0" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "Не вдалося виконати пошук нових образів" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "Не вдалося запустити роботу контейнера $0" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "Не вдалося запустити кокон $0" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "Не вдалося зупинити роботу контейнера $0" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "Не вдалося зупинити кокон $0" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "Помилкова смужка" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "Примусово внести" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "Примусове вилучення" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "Примусово вилучити кокон $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "Примусовий перезапуск" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "Примусово зупинити" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "ГБ" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "Шлюз" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "Перевірка працездатності" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "Довідка з інтервалу перевірки працездатності" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "Довідка з повторних спроб перевірки працездатності" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "Довідка із початкового періоду перевірки працездатності" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "Довідка з часу очікування перевірки працездатності" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "Довідка щодо дії при перевірці небезпечності стану" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "Працездатний" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "Приховати образи" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "Приховати проміжні образи" + +#: src/Images.jsx:158 +msgid "History" +msgstr "Журнал" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "Шлях у основній системі" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "Порт в основній системі" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "Довідка щодо порту в основній системі" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "Ід." + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP-адреса" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "Довідка щодо IP-адреси" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "Ідеальне для розробки" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "Ідеальне для запуску служб" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "" +"Якщо встановлено IP-адресу основної системи 0.0.0.0 або адресу не " +"встановлено взагалі, порт буде пов'язано із усіма IP-адресами в основній " +"системі." + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "" +"Якщо порт в основній системі не встановлено, порт контейнера буде випадковим " +"чином пов'язано із портом в основній системі." + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "Ігнорувати IP-адресу, якщо її встановлено статично" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "Ігнорувати MAC-адресу, якщо її встановлено статично" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "Образ" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "Назва образу не є унікальною" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "Слід вказати назву образу" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "Довідка щодо вибору образу" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "Образи" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "Збільшити спільне використання процесора" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "Збільшити інтервал" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "Збільшити максимум повторних спроб" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "Збільшити пам'ять" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "Збільшити кількість повторних спроб" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "Збільшити початковий період" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "Збільшити час очікування" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "Інтеграція" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "Інтервал" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "Частота запуску перевірки працездатності." + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "" +"Некоректні символи. Назва може складатися лише з літер, цифр та деяких " +"символів пунктуації (_ . -)." + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "кБ" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "Зберігати усі тимчасові файли контрольних точок" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "Ключ" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "Останні 5 запусків" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "Найсвіжіша контрольна точка" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "Лишати запущеним після запису контрольної точки на диск" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "Завантаження подробиць…" + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "Завантаження журналу…" + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "Завантаження…" + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "Локальний" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "Локальні образи" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "Журнал" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC-адреса" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "МБ" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "Максимум повторних спроб" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "Пам'ять" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "Обмеження пам’яті" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "Одиниця пам’яті" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "Режим" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "" +"Для цього образу існує декілька міток. Виберіть позначені міткою образи для " +"вилучення." + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "Назва" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "Назва нового контейнера" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "Назва нового образу" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "Ні" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "Без дії" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "Немає контейнерів" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "Цей образ не використовує жоден контейнер" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "У цьому коконі немає контейнерів" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "Немає контейнерів, які проходять поточні умови фільтрування" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "Змінних середовища не визначено" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "Немає образів" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "Образів не знайдено" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "Немає образів, які проходять поточні умови фільтрування" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "Немає мітки" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "Не відкрито жодного порту" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "Немає результатів, що відповідають $0" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "Немає запущених контейнерів" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "Томів не визначено" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "При помилці" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "Лише запущені" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "Параметри" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "Власник" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "Довідка щодо власника" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "Перевірку працездатності пройдено" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "" +"Вставте один або декілька рядків у форматі парт «ключ=значення» до будь-" +"якого поля для пакетного імпортування" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "Призупинити" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "Призупинити роботу контейнера при створенні образу" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "Призупинено" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "Не вдалося створити стручок" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Назва стручка" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Контейнери Docker" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Служба Docker є неактивною" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "Прив'язка портів" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "Порти" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "Можна прив'язувати порти нижче 1024" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "Приватний" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "Протокол" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "Позбутися" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "Позбутися невикористаних контейнерів" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "Позбутися невикористаних образів" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "Очищуємо контейнери" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "Позбуваємося образів" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "Отримати найсвіжіший образ" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "Отримання даних" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "Доступ лише до читання" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "Доступ до читання і запису" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "Вилучити запис" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "Вилучає позначені незапущені контейнери" + +#: src/util.js:23 +msgid "Removing" +msgstr "Вилучення" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "Перейменувати" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "Перейменувати контейнер $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "Можна встановлювати обмеження на ресурси" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "Перезапустити" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "Правила перезапуску" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "Довідка щодо правил перезапуску" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "Правила перезапуску, які слід виконувати при виході з контейнерів." + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"Перезапускати правила після виходу з контейнерів. Використання очікування " +"для автозапуску контейнерів може за певних обставин не працювати, зокрема " +"воно не працює, якщо для облікового запису користувача використано ecryptfs, " +"systemd-homed, NFS або 2FA." + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "Відновити" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "Відновити контейнер $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "Відновити із встановленими з'єднаннями TCP" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "Обмежено правами доступу до облікового запису користувача" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "Продовжити" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "Повторні спроби" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "Повторіть спробу із іншим ключем пошуку." + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "Виконати перевірку працездатності" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "Запущено" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "Шукати за назвою і описом" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "Шукати за реєстром" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "Шукати" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "Шукати образ" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "Рядок для пошуку або розташування контейнера" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "Пошук…" + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "Шукаємо: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "Спільний" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "Показати" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "Показати образи" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "Показати проміжні образи" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "Стислий показ" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "Додаткові відомості" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "Розмір" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "Запустити" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "Початковий період" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "Запустити docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "Почніть щось вводити, щоб виконати пошук образів." + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "Запущено" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "Стан" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "Стан" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "Зупинити" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "Зупинено" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "Підтримка збереження встановлених з'єднань TCP" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "Система" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "Також доступна загальносистемна служба Docker" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "Мітка" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "Мітки" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Інтерфейс користувача Cockpit для контейнерів Docker." + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "Час ініціалізації, потрібний контейнеру для самозапуску." + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "" +"Максимальний припустимий час для завершення перевірки працездатності до " +"моменту реєстрації помилки." + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "" +"Кількість повторних спроб, якими можна скористатися, доки перевірка " +"працездатності вважатиметься непройденою." + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "Час очікування" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "Діагностика проблем" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "Введіть щось для фільтрування…" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "Не вдалося завантажити журнал образу" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "Непрацездатний" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "Працює з $0" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "Скористатися застарілим форматом Docker" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "Використовується" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "Користувач" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "Також доступна служба користувачів Docker" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "Користувач:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "Значення" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "Томи" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "Якщо непрацездатні" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "За допомогою термінала" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "Придатний до запису" + +#: src/manifest.json:0 +msgid "container" +msgstr "контейнер" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "отримання" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "вузол[:порт]/[користувач]/контейнер[:мітка]" + +#: src/manifest.json:0 +msgid "image" +msgstr "образ" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "у" + +#: src/ImageDeleteModal.jsx:79 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate" +msgstr "Приховати проміжні образи" + +#: src/ImageDeleteModal.jsx:59 +#, fuzzy +#| msgid "Hide intermediate images" +msgid "intermediate image" +msgstr "Приховати проміжні образи" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "н/д" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "не доступне" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "група коконів" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "порти" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "секунд" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "система" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "не використано" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "користувач:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "томи" + +#~ msgid "Delete $0" +#~ msgstr "Вилучити $0" + +#~ msgid "select all" +#~ msgstr "вибрати все" + +#~ msgid "Failure action" +#~ msgstr "Дія при критичній помилці" + +#~ msgid "Restarting" +#~ msgstr "Перезапуск" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "Підтвердьте вилучення $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "Підтвердьте вилучення кокона $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "Підтвердьте примусове вилучення кокона $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "Підтвердьте примусове вилучення $0" + +#~ msgid "Container is currently running." +#~ msgstr "Контейнер працює." + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "Не включати зміни у кореневій файловій системі при експортуванні" + +#~ msgid "Default with single selectable" +#~ msgstr "Типове із одним варіантом вибору" + +#~ msgid "Start after creation" +#~ msgstr "Запустити після створення" + +#~ msgid "Delete unused $0 images:" +#~ msgstr "Вилучити невикористані $0 образів:" + +#~ msgid "created" +#~ msgstr "створено" + +#~ msgid "exited" +#~ msgstr "здійснено вихід" + +#~ msgid "paused" +#~ msgstr "призупинено" + +#~ msgid "running" +#~ msgstr "працює" + +#~ msgid "stopped" +#~ msgstr "зупинився" + +#~ msgid "user" +#~ msgstr "користувач" + +#~ msgid "Add on build variable" +#~ msgstr "Додати змінну збирання" + +#~ msgid "Commit image" +#~ msgstr "Надіслати образ" + +#~ msgid "Format" +#~ msgstr "Формат" + +#~ msgid "Message" +#~ msgstr "Повідомлення" + +#~ msgid "Pause the container" +#~ msgstr "Призупинити роботу контейнера" + +#~ msgid "Remove on build variable" +#~ msgstr "Встановити змінну збирання" + +#~ msgid "Set container on build variables" +#~ msgstr "Встановити змінні збирання контейнера" + +#~ msgid "Add item" +#~ msgstr "Додати запис" + +#~ msgid "Host port (optional)" +#~ msgstr "Порт основної системи (необов'язковий)" + +#~ msgid "IP (optional)" +#~ msgstr "IP-адреса (необов'язкова)" + +#~ msgid "ReadOnly" +#~ msgstr "Лише читання" + +#~ msgid "IP prefix length" +#~ msgstr "Довжина префікса IP" + +#~ msgid "Get new image" +#~ msgstr "Отримати новий образ" + +#~ msgid "Run" +#~ msgstr "Запустити" + +#~ msgid "On build" +#~ msgstr "При збиранні" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "Ви справді хочете вилучити цей образ?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "Не вдалося долучитися до цього контейнера: $0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "Не вдалося відкрити канал: $0" + +#~ msgid "Everything" +#~ msgstr "Все" + +#~ msgid "Security" +#~ msgstr "Безпека" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "Скануванням від $time ($type) вразливостей не знайдено." + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "У цій версії Web Console не передбачено підтримки терміналів." diff --git a/ui/cockpit-docker/po/zh_CN.po b/ui/cockpit-docker/po/zh_CN.po new file mode 100644 index 0000000..37ac1bc --- /dev/null +++ b/ui/cockpit-docker/po/zh_CN.po @@ -0,0 +1,1479 @@ +# #-#-#-#-# docker.js.pot (PACKAGE VERSION) #-#-#-#-# +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Pany , 2020. +# Harry Chen , 2020. +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE_VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-11 02:46+0000\n" +"PO-Revision-Date: 2023-12-22 22:18+0000\n" +"Last-Translator: Jingge Chen \n" +"Language-Team: Chinese (Simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0\n" +"X-Generator: Weblate 5.3\n" + +#: src/Images.jsx:89 +msgid "$0 container" +msgid_plural "$0 containers" +msgstr[0] "$0容器" + +#: src/Images.jsx:271 +msgid "$0 image total, $1" +msgid_plural "$0 images total, $1" +msgstr[0] "共$0个镜像,$1" + +#: src/ContainerHealthLogs.jsx:35 +msgid "$0 second" +msgid_plural "$0 seconds" +msgstr[0] "$0 秒" + +#: src/Images.jsx:275 +msgid "$0 unused image, $1" +msgid_plural "$0 unused images, $1" +msgstr[0] "$0个未使用镜像,$1" + +#: src/PublishPort.jsx:30 src/PublishPort.jsx:41 +msgid "1 to 65535" +msgstr "1 到 65535" + +#: src/ImageRunModal.jsx:1134 +msgid "Action to take once the container transitions to an unhealthy state." +msgstr "容器转换到不健康状态后要执行的操作。" + +#: src/PodCreateModal.jsx:179 src/ImageRunModal.jsx:995 +msgid "Add port mapping" +msgstr "添加端口映射" + +#: src/ImageRunModal.jsx:1017 +msgid "Add variable" +msgstr "添加变量" + +#: src/PodCreateModal.jsx:191 src/ImageRunModal.jsx:1005 +msgid "Add volume" +msgstr "添加卷" + +#: src/ContainerHeader.jsx:21 src/Containers.jsx:730 +#: src/ImageDeleteModal.jsx:104 src/ImageRunModal.jsx:702 +msgid "All" +msgstr "所有" + +#: src/ImageSearchModal.jsx:176 +msgid "All registries" +msgstr "所有 registry" + +#: src/ImageRunModal.jsx:965 +msgid "Always" +msgstr "总是" + +#: src/PodActions.jsx:57 +msgid "An error occurred" +msgstr "发生了错误" + +#: src/ContainerCommitModal.jsx:105 +msgid "Author" +msgstr "作者" + +#: src/app.jsx:641 +msgid "Automatically start docker on boot" +msgstr "开机自动启动 docker" + +#: src/Containers.jsx:505 src/Containers.jsx:508 src/Containers.jsx:567 +msgid "CPU" +msgstr "CPU" + +#: src/ImageRunModal.jsx:918 +msgid "CPU Shares help" +msgstr "CPU 份额帮助" + +#: src/ImageRunModal.jsx:916 +msgid "CPU shares" +msgstr "CPU 份额" + +#: src/ImageRunModal.jsx:920 +msgid "" +"CPU shares determine the priority of running containers. Default priority is " +"1024. A higher number prioritizes this container. A lower number decreases " +"priority." +msgstr "" +"CPU 份额决定了运行容器的优先级。默认优先级为 1024。数字越大,容器的优先级越" +"高。数字越小,优先级越低。" + +#: src/PodCreateModal.jsx:213 src/PruneUnusedContainersModal.jsx:96 +#: src/PodActions.jsx:52 src/ContainerCommitModal.jsx:157 +#: src/ContainerDeleteModal.jsx:34 src/ContainerRestoreModal.jsx:53 +#: src/ImageDeleteModal.jsx:98 src/PruneUnusedImagesModal.jsx:97 +#: src/ImageRunModal.jsx:1175 src/ContainerRenameModal.jsx:97 +#: src/ImageSearchModal.jsx:152 src/ForceRemoveModal.jsx:25 +#: src/ContainerCheckpointModal.jsx:50 +msgid "Cancel" +msgstr "取消" + +#: src/Containers.jsx:286 +msgid "Checking health" +msgstr "检查健康状况" + +#: src/Containers.jsx:207 src/ContainerCheckpointModal.jsx:46 +msgid "Checkpoint" +msgstr "检查点" + +#: src/ImageRunModal.jsx:775 +msgid "Checkpoint and restore support" +msgstr "检查点和恢复支持" + +#: src/ContainerCheckpointModal.jsx:41 +msgid "Checkpoint container $0" +msgstr "检查点容器 $0" + +#: src/Containers.jsx:523 +msgid "Click to see published ports" +msgstr "点击以查看公布的端口" + +#: src/Containers.jsx:538 +msgid "Click to see volumes" +msgstr "点击以查看卷" + +#: org.cockpit-project.docker.metainfo.xml:6 +msgid "Cockpit component for Docker containers" +msgstr "Docker 容器的 Cockpit 组件" + +#: src/ContainerCommitModal.jsx:112 src/ContainerHealthLogs.jsx:60 +#: src/ImageRunModal.jsx:871 src/ImageRunModal.jsx:1026 +#: src/ContainerDetails.jsx:39 src/ImageDetails.jsx:15 +msgid "Command" +msgstr "命令" + +#: src/ImageHistory.jsx:33 +msgid "Comments" +msgstr "注释" + +#: src/ContainerCommitModal.jsx:144 src/Containers.jsx:242 +msgid "Commit" +msgstr "提交" + +#: src/ContainerCommitModal.jsx:136 +msgid "Commit container" +msgstr "提交容器" + +#: src/util.js:23 +msgid "Configured" +msgstr "已配置" + +#: src/Containers.jsx:432 +msgid "Console" +msgstr "控制台" + +#: src/Containers.jsx:565 +msgid "Container" +msgstr "容器" + +#: src/ImageRunModal.jsx:258 +msgid "Container failed to be created" +msgstr "容器创建失败" + +#: src/ImageRunModal.jsx:241 +msgid "Container failed to be started" +msgstr "容器启动失败" + +#: src/ContainerTerminal.jsx:259 +msgid "Container is not running" +msgstr "容器未运行" + +#: src/ImageRunModal.jsx:742 +msgid "Container name" +msgstr "容器名称" + +#: src/ContainerRenameModal.jsx:28 src/ContainerRenameModal.jsx:39 +msgid "Container name is required." +msgstr "容器名称是必需的。" + +#: src/Volume.jsx:50 +msgid "Container path" +msgstr "容器路径" + +#: src/Volume.jsx:23 +msgid "Container path must not be empty" +msgstr "容器路径不能为空" + +#: src/PublishPort.jsx:105 +msgid "Container port" +msgstr "容器端口" + +#: src/PublishPort.jsx:37 +msgid "Container port must not be empty" +msgstr "容器端口不能为空" + +#: src/Containers.jsx:784 src/Containers.jsx:790 src/Containers.jsx:820 +msgid "Containers" +msgstr "容器" + +#: src/PodCreateModal.jsx:210 src/ImageRunModal.jsx:1172 +msgid "Create" +msgstr "创建" + +#: src/ContainerCommitModal.jsx:137 +msgid "Create a new image based on the current state of the $0 container." +msgstr "根据 $0 容器的当前状态创建一个新镜像。" + +#: src/ImageRunModal.jsx:1169 +msgid "Create and run" +msgstr "创建并运行" + +#: src/Containers.jsx:747 src/ImageRunModal.jsx:1166 src/Images.jsx:402 +#: src/Images.jsx:411 +msgid "Create container" +msgstr "创建容器" + +#: src/ImageRunModal.jsx:1166 +msgid "Create container in $0" +msgstr "在 $0 中创建容器" + +#: src/Containers.jsx:830 +msgid "Create container in pod" +msgstr "在 pod 中创建容器" + +#: src/PodCreateModal.jsx:206 src/Containers.jsx:739 +msgid "Create pod" +msgstr "创建 pod" + +#: src/PruneUnusedContainersModal.jsx:65 src/util.js:23 src/util.js:26 +#: src/ImageHistory.jsx:33 src/Images.jsx:180 src/ContainerDetails.jsx:63 +msgid "Created" +msgstr "已创建" + +#: src/ImageHistory.jsx:33 +msgid "Created by" +msgstr "创建" + +#: src/ImageRunModal.jsx:939 +msgid "Decrease CPU shares" +msgstr "减少 CPU 共享" + +#: src/ImageRunModal.jsx:1049 +msgid "Decrease interval" +msgstr "缩短间隔" + +#: src/ImageRunModal.jsx:978 +msgid "Decrease maximum retries" +msgstr "减小最大重试次数" + +#: src/ImageRunModal.jsx:897 +msgid "Decrease memory" +msgstr "减少内存" + +#: src/ImageRunModal.jsx:1123 +msgid "Decrease retries" +msgstr "减少重试" + +#: src/ImageRunModal.jsx:1099 +msgid "Decrease start period" +msgstr "减少启动周期" + +#: src/ImageRunModal.jsx:1074 +msgid "Decrease timeout" +msgstr "减少超时" + +#: src/PodActions.jsx:48 src/PodActions.jsx:181 src/ContainerDeleteModal.jsx:33 +#: src/Containers.jsx:261 src/Images.jsx:417 +msgid "Delete" +msgstr "删除" + +#: src/ImageDeleteModal.jsx:92 +msgid "Delete $0 image?" +msgstr "删除 $0 图片?" + +#: src/ContainerDeleteModal.jsx:31 src/ForceRemoveModal.jsx:18 +msgid "Delete $0?" +msgstr "删除 $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete image" +msgstr "删除镜像" + +#: src/PodActions.jsx:43 +msgid "Delete pod $0?" +msgstr "删除 pod $0?" + +#: src/ImageDeleteModal.jsx:96 +msgid "Delete tagged images" +msgstr "删除标记的镜像" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused system images:" +msgstr "删除未使用的系统镜像:" + +#: src/PruneUnusedImagesModal.jsx:32 +msgid "Delete unused user images:" +msgstr "删除未使用的用户镜像:" + +#: src/ContainerDeleteModal.jsx:37 +msgid "Deleting a container will erase all data in it." +msgstr "删除容器会清空其中的全部数据。" + +#: src/Containers.jsx:70 +msgid "Deleting a running container will erase all data in it." +msgstr "删除正在运行的容器将会清除其中的所有数据。" + +#: src/PodActions.jsx:63 +msgid "Deleting this pod will remove the following containers:" +msgstr "删除这个 Pod 将会移除这些容器:" + +#: src/Containers.jsx:415 src/ImageRunModal.jsx:757 src/Images.jsx:149 +msgid "Details" +msgstr "详情" + +#: src/Images.jsx:182 +msgid "Disk space" +msgstr "磁盘空间" + +#: src/ContainerCommitModal.jsx:126 +msgid "" +"Docker format is useful when sharing the image with Docker or Moby Engine" +msgstr "当与 Docker 或 Moby Engine 共享镜像时,Docker 格式非常有用" + +#: src/ImageSearchModal.jsx:149 +msgid "Download" +msgstr "下载" + +#: src/Images.jsx:339 +msgid "Download new image" +msgstr "现在新镜像" + +#: src/PodActions.jsx:59 +msgid "Empty pod $0 will be permanently removed." +msgstr "空 pod $0 将被永久删除。" + +#: src/ImageRunModal.jsx:866 src/ImageDetails.jsx:21 +msgid "Entrypoint" +msgstr "入口点" + +#: src/ContainerIntegration.jsx:114 src/ImageRunModal.jsx:1016 +msgid "Environment variables" +msgstr "环境变量" + +#: src/util.js:26 +msgid "Error" +msgstr "错误" + +#: src/Images.jsx:58 src/Notification.jsx:42 +msgid "Error message" +msgstr "错误信息" + +#: src/ContainerTerminal.jsx:263 +msgid "Error occurred while connecting console" +msgstr "连接到控制台时出现错误" + +#: src/ContainerCommitModal.jsx:107 +msgid "Example, Your Name " +msgstr "示例,您的名字 " + +#: src/ImageRunModal.jsx:821 +msgid "Example: $0" +msgstr "示例:$0" + +#: src/util.js:23 src/util.js:26 src/ContainerDetails.jsx:14 +msgid "Exited" +msgstr "已退出" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Failed health run" +msgstr "失败的健康运行" + +#: src/ContainerCheckpointModal.jsx:28 +msgid "Failed to checkpoint container $0" +msgstr "检查点容器 $0 失败" + +#: src/ImageRunModal.jsx:247 +msgid "Failed to clean up container" +msgstr "清理容器失败" + +#: src/ContainerCommitModal.jsx:81 +msgid "Failed to commit container $0" +msgstr "提交容器 $0 失败" + +#: src/ImageRunModal.jsx:312 +msgid "Failed to create container $0" +msgstr "创建容器 $0 失败" + +#: src/Images.jsx:55 +msgid "Failed to download image $0:$1" +msgstr "下载镜像 $0:$1 失败" + +#: src/Containers.jsx:59 +msgid "Failed to force remove container $0" +msgstr "强制移除容器 $0 失败" + +#: src/ImageDeleteModal.jsx:49 +msgid "Failed to force remove image $0" +msgstr "强制删除镜像失败 $0" + +#: src/PodActions.jsx:117 +msgid "Failed to force restart pod $0" +msgstr "强制重启 pod $0 失败" + +#: src/PodActions.jsx:95 +msgid "Failed to force stop pod $0" +msgstr "强制停止 Pod $0 失败" + +#: src/Containers.jsx:108 +msgid "Failed to pause container $0" +msgstr "暂停容器 $0 失败" + +#: src/PodActions.jsx:162 +msgid "Failed to pause pod $0" +msgstr "暂停 Pod $0 失败" + +#: src/PruneUnusedContainersModal.jsx:57 +msgid "Failed to prune unused containers" +msgstr "删除未使用的容器失败" + +#: src/PruneUnusedImagesModal.jsx:73 +msgid "Failed to prune unused images" +msgstr "删除未使用的映像失败" + +#: src/ImageRunModal.jsx:318 +msgid "Failed to pull image $0" +msgstr "拉取镜像 $0 失败" + +#: src/ContainerDeleteModal.jsx:21 +msgid "Failed to remove container $0" +msgstr "移除容器 $0 失败" + +#: src/ImageDeleteModal.jsx:73 +msgid "Failed to remove image $0" +msgstr "删除镜像 $0 失败" + +#: src/ContainerRenameModal.jsx:54 +msgid "Failed to rename container $0" +msgstr "重命名容器 $0 失败" + +#: src/Containers.jsx:133 +msgid "Failed to restart container $0" +msgstr "重启容器 $0 失败" + +#: src/PodActions.jsx:106 +msgid "Failed to restart pod $0" +msgstr "重启 pod $0 失败" + +#: src/ContainerRestoreModal.jsx:31 +msgid "Failed to restore container $0" +msgstr "恢复容器 $0 失败" + +#: src/Containers.jsx:100 +msgid "Failed to resume container $0" +msgstr "恢复容器 $0 失败" + +#: src/PodActions.jsx:147 +msgid "Failed to resume pod $0" +msgstr "恢复 Pod $0 失败" + +#: src/ImageRunModal.jsx:305 +msgid "Failed to run container $0" +msgstr "运行容器 $0 失败" + +#: src/Containers.jsx:121 src/ContainerHealthLogs.jsx:94 +msgid "Failed to run health check on container $0" +msgstr "在容器 $0 上运行健康检查失败" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images." +msgstr "搜索镜像失败。" + +#: src/ImageRunModal.jsx:399 src/ImageSearchModal.jsx:93 +msgid "Failed to search for images: $0" +msgstr "搜索镜像 $0 失败" + +#: src/ImageRunModal.jsx:397 src/ImageSearchModal.jsx:92 +msgid "Failed to search for new images" +msgstr "搜索新镜像失败" + +#: src/Containers.jsx:92 +msgid "Failed to start container $0" +msgstr "启动容器 $0 失败" + +#: src/PodActions.jsx:132 +msgid "Failed to start pod $0" +msgstr "启动 Pod $0 失败" + +#: src/Containers.jsx:84 +msgid "Failed to stop container $0" +msgstr "停止容器 $0 失败" + +#: src/PodActions.jsx:84 +msgid "Failed to stop pod $0" +msgstr "停止 Pod $0 失败" + +#: src/ContainerHealthLogs.jsx:84 +msgid "Failing streak" +msgstr "streak 失败" + +#: src/ContainerCommitModal.jsx:151 +msgid "Force commit" +msgstr "强制提交" + +#: src/PodActions.jsx:48 src/ForceRemoveModal.jsx:23 +msgid "Force delete" +msgstr "强制删除" + +#: src/PodActions.jsx:42 +msgid "Force delete pod $0?" +msgstr "强制删除 pod $0?" + +#: src/PodActions.jsx:121 src/Containers.jsx:182 +msgid "Force restart" +msgstr "强制重启" + +#: src/PodActions.jsx:99 src/Containers.jsx:174 src/ContainerHealthLogs.jsx:42 +#: src/ImageRunModal.jsx:61 +msgid "Force stop" +msgstr "强制停止" + +#: src/ImageRunModal.jsx:908 +msgid "GB" +msgstr "GB" + +#: src/ContainerDetails.jsx:51 +msgid "Gateway" +msgstr "网关" + +#: src/Containers.jsx:441 src/ImageRunModal.jsx:1025 +msgid "Health check" +msgstr "健康检查" + +#: src/ImageRunModal.jsx:1034 +msgid "Health check interval help" +msgstr "健康检查间隔帮助" + +#: src/ImageRunModal.jsx:1109 +msgid "Health check retries help" +msgstr "健康检查重试帮助" + +#: src/ImageRunModal.jsx:1084 +msgid "Health check start period help" +msgstr "健康检查启动周期帮助" + +#: src/ImageRunModal.jsx:1059 +msgid "Health check timeout help" +msgstr "健康检查超时帮助" + +#: src/ImageRunModal.jsx:1132 +msgid "Health failure check action help" +msgstr "健康检查失败操作帮助" + +#: src/Containers.jsx:282 +msgid "Healthy" +msgstr "健康" + +#: src/Images.jsx:302 +msgid "Hide images" +msgstr "隐藏镜像" + +#: src/Images.jsx:252 +msgid "Hide intermediate images" +msgstr "隐藏中间镜像" + +#: src/Images.jsx:158 +msgid "History" +msgstr "历史" + +#: src/Volume.jsx:36 +msgid "Host path" +msgstr "主机路径" + +#: src/PublishPort.jsx:78 +msgid "Host port" +msgstr "主机端口" + +#: src/PublishPort.jsx:81 +msgid "Host port help" +msgstr "主机端口帮助" + +#: src/Images.jsx:181 src/ContainerDetails.jsx:31 +msgid "ID" +msgstr "ID" + +#: src/ContainerDetails.jsx:47 src/PublishPort.jsx:55 +msgid "IP address" +msgstr "IP 地址" + +#: src/PublishPort.jsx:58 +msgid "IP address help" +msgstr "IP 地址帮助" + +#: src/ImageRunModal.jsx:786 +msgid "Ideal for development" +msgstr "非常适合开发" + +#: src/ImageRunModal.jsx:769 +msgid "Ideal for running services" +msgstr "非常适合运行服务" + +#: src/PublishPort.jsx:60 +msgid "" +"If host IP is set to 0.0.0.0 or not set at all, the port will be bound on " +"all IPs on the host." +msgstr "如果主机 IP 设置为 0.0.0.0 或没有设置,端口将被绑定到主机上的所有 IP。" + +#: src/PublishPort.jsx:83 +msgid "" +"If the host port is not set the container port will be randomly assigned a " +"port on the host." +msgstr "如果主机端口没有设置,容器端口将被随机分配到主机上的一个端口。" + +#: src/ContainerRestoreModal.jsx:63 +msgid "Ignore IP address if set statically" +msgstr "如果以静态方式设置,则忽略 IP 地址" + +#: src/ContainerRestoreModal.jsx:66 +msgid "Ignore MAC address if set statically" +msgstr "忽略被静态设定的 MAC 地址" + +#: src/ImageRunModal.jsx:814 src/Images.jsx:178 src/ContainerDetails.jsx:35 +msgid "Image" +msgstr "镜像" + +#: src/ContainerCommitModal.jsx:44 +msgid "Image name is not unique" +msgstr "镜像名称不是唯一的" + +#: src/ContainerCommitModal.jsx:35 +msgid "Image name is required" +msgstr "镜像名称是必需的" + +#: src/ImageRunModal.jsx:816 +msgid "Image selection help" +msgstr "镜像选择帮助" + +#: src/Images.jsx:258 src/Images.jsx:288 +msgid "Images" +msgstr "镜像" + +#: src/ImageRunModal.jsx:940 +msgid "Increase CPU shares" +msgstr "增加 CPU 共享" + +#: src/ImageRunModal.jsx:1050 +msgid "Increase interval" +msgstr "增加间隔" + +#: src/ImageRunModal.jsx:979 +msgid "Increase maximum retries" +msgstr "增加最大重试次数" + +#: src/ImageRunModal.jsx:898 +msgid "Increase memory" +msgstr "增加内存" + +#: src/ImageRunModal.jsx:1124 +msgid "Increase retries" +msgstr "增加重试" + +#: src/ImageRunModal.jsx:1100 +msgid "Increase start period" +msgstr "增加开始周期" + +#: src/ImageRunModal.jsx:1075 +msgid "Increase timeout" +msgstr "增加超时" + +#: src/Containers.jsx:422 src/ImageRunModal.jsx:989 +msgid "Integration" +msgstr "集成" + +#: src/ContainerHealthLogs.jsx:64 src/ImageRunModal.jsx:1032 +msgid "Interval" +msgstr "间隔" + +#: src/ImageRunModal.jsx:1036 +msgid "Interval how often health check is run." +msgstr "健康检查运行的频率间隔。" + +#: src/PodCreateModal.jsx:113 src/ContainerRenameModal.jsx:32 +msgid "" +"Invalid characters. Name can only contain letters, numbers, and certain " +"punctuation (_ . -)." +msgstr "无效的字符。名称只能包含字母、数字和某些标点符号 (_ . -)。" + +#: src/ImageRunModal.jsx:906 +msgid "KB" +msgstr "KB" + +#: src/ContainerRestoreModal.jsx:58 src/ContainerCheckpointModal.jsx:55 +msgid "Keep all temporary checkpoint files" +msgstr "保留所有临时检查点文件" + +#: src/Env.jsx:56 +msgid "Key" +msgstr "键" + +#: src/Env.jsx:18 +msgid "Key must not be empty" +msgstr "键不能为空" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Last 5 runs" +msgstr "最后 5 个运行" + +#: src/ContainerDetails.jsx:71 +msgid "Latest checkpoint" +msgstr "最新的检查点" + +#: src/ContainerCheckpointModal.jsx:57 +msgid "Leave running after writing checkpoint to disk" +msgstr "在将检查点写入磁盘后保持运行" + +#: src/ImageHistory.jsx:59 src/ContainerIntegration.jsx:93 +msgid "Loading details..." +msgstr "加载详细信息..." + +#: src/ContainerLogs.jsx:54 +msgid "Loading logs..." +msgstr "正在加载日志..." + +#: src/Containers.jsx:579 src/ImageUsedBy.jsx:12 +msgid "Loading..." +msgstr "加载中……" + +#: src/ImageRunModal.jsx:711 +msgid "Local" +msgstr "本地" + +#: src/ImageRunModal.jsx:502 +msgid "Local images" +msgstr "本地镜像" + +#: src/Containers.jsx:427 src/ContainerHealthLogs.jsx:102 +msgid "Logs" +msgstr "日志" + +#: src/ContainerDetails.jsx:55 +msgid "MAC address" +msgstr "MAC 地址" + +#: src/ImageRunModal.jsx:907 +msgid "MB" +msgstr "MB" + +#: src/ImageRunModal.jsx:971 +msgid "Maximum retries" +msgstr "最大重试次数" + +#: src/Containers.jsx:512 src/Containers.jsx:515 src/Containers.jsx:568 +msgid "Memory" +msgstr "内存" + +#: src/ImageRunModal.jsx:884 +msgid "Memory limit" +msgstr "内存限制" + +#: src/ImageRunModal.jsx:901 +msgid "Memory unit" +msgstr "内存单元" + +#: src/Volume.jsx:64 +msgid "Mode" +msgstr "模式" + +#: src/ImageDeleteModal.jsx:102 +msgid "Multiple tags exist for this image. Select the tagged images to delete." +msgstr "此镜像存在多个标签。选择标记的镜像以删除。" + +#: src/PublishPort.jsx:24 +msgid "Must be a valid IP address" +msgstr "必须是有效的 IP 地址" + +#: src/PodCreateModal.jsx:144 src/PruneUnusedContainersModal.jsx:64 +#: src/ImageRunModal.jsx:739 +msgid "Name" +msgstr "名称" + +#: src/ImageRunModal.jsx:612 +msgid "Name already in use" +msgstr "名称已被使用" + +#: src/ContainerRenameModal.jsx:68 +msgid "New container name" +msgstr "新容器名称" + +#: src/ContainerCommitModal.jsx:90 +msgid "New image name" +msgstr "新镜像名称" + +#: src/ImageRunModal.jsx:963 +msgid "No" +msgstr "否" + +#: src/ContainerHealthLogs.jsx:39 src/ImageRunModal.jsx:58 +msgid "No action" +msgstr "无操作" + +#: src/Containers.jsx:576 +msgid "No containers" +msgstr "没有容器" + +#: src/ImageUsedBy.jsx:14 +msgid "No containers are using this image" +msgstr "没有使用该镜像的容器" + +#: src/Containers.jsx:577 +msgid "No containers in this pod" +msgstr "此 pod 中没有容器" + +#: src/Containers.jsx:581 +msgid "No containers that match the current filter" +msgstr "没有符合当前筛选条件的容器" + +#: src/ImageRunModal.jsx:1014 +msgid "No environment variables specified" +msgstr "没有指定环境变量" + +#: src/Images.jsx:185 +msgid "No images" +msgstr "没有镜像" + +#: src/ImageRunModal.jsx:839 src/ImageSearchModal.jsx:185 +msgid "No images found" +msgstr "没有找到镜像" + +#: src/Images.jsx:189 +msgid "No images that match the current filter" +msgstr "没有符合当前筛选条件的镜像" + +#: src/Volume.jsx:75 +msgid "No label" +msgstr "无标签" + +#: src/PodCreateModal.jsx:176 src/ImageRunModal.jsx:992 +msgid "No ports exposed" +msgstr "没有公开的端口" + +#: src/ImageSearchModal.jsx:189 +msgid "No results for $0" +msgstr "没有 $0 的结果" + +#: src/Containers.jsx:583 +msgid "No running containers" +msgstr "没有正在运行的容器" + +#: src/PodCreateModal.jsx:188 src/ImageRunModal.jsx:1002 +msgid "No volumes specified" +msgstr "没有指定卷" + +#: src/ImageRunModal.jsx:964 +msgid "On failure" +msgstr "失败时" + +#: src/Containers.jsx:731 +msgid "Only running" +msgstr "仅运行" + +#: src/ContainerCommitModal.jsx:118 +msgid "Options" +msgstr "选项" + +#: src/PodCreateModal.jsx:162 src/PruneUnusedContainersModal.jsx:69 +#: src/ContainerHeader.jsx:15 src/Containers.jsx:566 src/ImageRunModal.jsx:759 +#: src/Images.jsx:179 src/ImageSearchModal.jsx:159 +msgid "Owner" +msgstr "所有者" + +#: src/ImageRunModal.jsx:761 +msgid "Owner help" +msgstr "所有者帮助" + +#: src/ContainerHealthLogs.jsx:115 +msgid "Passed health run" +msgstr "通过的健康运行" + +#: src/ImageRunModal.jsx:1022 +msgid "" +"Paste one or more lines of key=value pairs into any field for bulk import" +msgstr "将一个或多个 key=value 对行粘贴到批量导入的任何字段" + +#: src/PodActions.jsx:166 src/Containers.jsx:190 +msgid "Pause" +msgstr "暂停" + +#: src/ContainerCommitModal.jsx:122 +msgid "Pause container when creating image" +msgstr "创建镜像时暂停容器" + +#: src/util.js:23 src/util.js:26 +msgid "Paused" +msgstr "已暂停" + +#: src/PodCreateModal.jsx:89 +msgid "Pod failed to be created" +msgstr "创建 Pod 失败" + +#: src/PodCreateModal.jsx:147 +msgid "Pod name" +msgstr "Pod 名称" + +#: org.cockpit-project.docker.metainfo.xml:5 +msgid "Docker" +msgstr "Docker" + +#: src/index.html:20 src/manifest.json:0 +msgid "Docker containers" +msgstr "Docker 容器" + +#: src/app.jsx:637 +msgid "Docker service is not active" +msgstr "Docker 服务未激活" + +#: src/PodCreateModal.jsx:178 src/ImageRunModal.jsx:994 +msgid "Port mapping" +msgstr "端口映射" + +#: src/ContainerIntegration.jsx:106 src/ImageDetails.jsx:39 +msgid "Ports" +msgstr "端口" + +#: src/ImageRunModal.jsx:778 +msgid "Ports under 1024 can be mapped" +msgstr "1024 以下的端口可以映射" + +#: src/Volume.jsx:77 +msgid "Private" +msgstr "私有" + +#: src/PublishPort.jsx:122 +msgid "Protocol" +msgstr "协议" + +#: src/PruneUnusedContainersModal.jsx:94 src/PruneUnusedImagesModal.jsx:95 +msgid "Prune" +msgstr "删除" + +#: src/PruneUnusedContainersModal.jsx:87 src/Containers.jsx:300 +msgid "Prune unused containers" +msgstr "删除未使用的容器" + +#: src/PruneUnusedImagesModal.jsx:88 src/Images.jsx:350 +msgid "Prune unused images" +msgstr "删除未使用的镜像" + +#: src/PruneUnusedContainersModal.jsx:90 src/PruneUnusedContainersModal.jsx:94 +msgid "Pruning containers" +msgstr "正在删除容器" + +#: src/PruneUnusedImagesModal.jsx:91 src/PruneUnusedImagesModal.jsx:95 +msgid "Pruning images" +msgstr "删除镜像" + +#: src/ImageRunModal.jsx:860 +msgid "Pull latest image" +msgstr "拉取最新的镜像" + +#: src/Images.jsx:325 +msgid "Pulling" +msgstr "正在拉取" + +#: src/ContainerIntegration.jsx:42 +msgid "Read-only access" +msgstr "只读访问" + +#: src/ContainerIntegration.jsx:41 +msgid "Read-write access" +msgstr "读写访问" + +#: src/Env.jsx:91 src/Volume.jsx:84 src/PublishPort.jsx:137 +msgid "Remove item" +msgstr "删除项目" + +#: src/PruneUnusedContainersModal.jsx:99 +msgid "Removes selected non-running containers" +msgstr "删除选择的、没有在运行的容器" + +#: src/util.js:23 +msgid "Removing" +msgstr "删除" + +#: src/Containers.jsx:160 src/ContainerRenameModal.jsx:92 +msgid "Rename" +msgstr "重命名" + +#: src/ContainerRenameModal.jsx:85 +msgid "Rename container $0" +msgstr "重命名容器 $0" + +#: src/ImageRunModal.jsx:772 +msgid "Resource limits can be set" +msgstr "可以设置资源限制" + +#: src/PodActions.jsx:110 src/util.js:23 src/Containers.jsx:178 +#: src/ContainerHealthLogs.jsx:40 src/ImageRunModal.jsx:59 +msgid "Restart" +msgstr "重启" + +#: src/ImageRunModal.jsx:948 +msgid "Restart policy" +msgstr "重启策略" + +#: src/ImageRunModal.jsx:950 src/ImageRunModal.jsx:960 +msgid "Restart policy help" +msgstr "重启策略帮助" + +#: src/ImageRunModal.jsx:952 +msgid "Restart policy to follow when containers exit." +msgstr "容器退出时遵循重启策略。" + +#: src/ImageRunModal.jsx:952 +msgid "" +"Restart policy to follow when containers exit. Using linger for auto-" +"starting containers may not work in some circumstances, such as when " +"ecryptfs, systemd-homed, NFS, or 2FA are used on a user account." +msgstr "" +"容器退出时重启策略。在某些情况下,使用 linger 进行自动启动容器可能无法正常工" +"作,如在用户账户中使用了 ecryptfs、systemd-homed、NFS 或 2FA。" + +#: src/Containers.jsx:228 src/ContainerRestoreModal.jsx:49 +msgid "Restore" +msgstr "恢复" + +#: src/ContainerRestoreModal.jsx:44 +msgid "Restore container $0" +msgstr "恢复容器 $0" + +#: src/ContainerRestoreModal.jsx:60 +msgid "Restore with established TCP connections" +msgstr "使用已建立的 TCP 连接恢复" + +#: src/ImageRunModal.jsx:789 +msgid "Restricted by user account permissions" +msgstr "受用户帐户权限限制" + +#: src/PodActions.jsx:151 src/Containers.jsx:197 +msgid "Resume" +msgstr "继续" + +#: src/ContainerHealthLogs.jsx:68 src/ImageRunModal.jsx:1107 +msgid "Retries" +msgstr "重试" + +#: src/ImageSearchModal.jsx:190 +msgid "Retry another term." +msgstr "重试另一个项。" + +#: src/Containers.jsx:251 src/ContainerHealthLogs.jsx:98 +msgid "Run health check" +msgstr "运行健康检查" + +#: src/util.js:23 src/util.js:26 src/ImageUsedBy.jsx:35 +msgid "Running" +msgstr "正在运行" + +#: src/Volume.jsx:71 +msgid "SELinux" +msgstr "SELinux" + +#: src/ImageSearchModal.jsx:167 +msgid "Search by name or description" +msgstr "按名称或描述搜索" + +#: src/ImageRunModal.jsx:701 +msgid "Search by registry" +msgstr "按照注册表搜索" + +#: src/ImageSearchModal.jsx:164 +msgid "Search for" +msgstr "搜索" + +#: src/ImageSearchModal.jsx:136 +msgid "Search for an image" +msgstr "搜索镜像" + +#: src/ImageRunModal.jsx:844 +msgid "Search string or container location" +msgstr "搜索字符串或容器位置" + +#: src/ImageSearchModal.jsx:183 +msgid "Searching..." +msgstr "搜索中..." + +#: src/ImageRunModal.jsx:822 +msgid "Searching: $0" +msgstr "搜索: $0" + +#: src/Volume.jsx:76 +msgid "Shared" +msgstr "共享" + +#: src/Containers.jsx:726 +msgid "Show" +msgstr "显示" + +#: src/Images.jsx:302 +msgid "Show images" +msgstr "显示镜像" + +#: src/Images.jsx:252 +msgid "Show intermediate images" +msgstr "显示中间镜像" + +#: src/ContainerIntegration.jsx:82 +msgid "Show less" +msgstr "显示更少" + +#: src/PruneUnusedImagesModal.jsx:48 src/ContainerIntegration.jsx:82 +msgid "Show more" +msgstr "显示更多" + +#: src/ImageHistory.jsx:33 +msgid "Size" +msgstr "大小" + +#: src/PodActions.jsx:136 src/app.jsx:683 src/Containers.jsx:217 +msgid "Start" +msgstr "启动" + +#: src/ContainerHealthLogs.jsx:72 src/ImageRunModal.jsx:1082 +msgid "Start period" +msgstr "开始期间" + +#: src/app.jsx:644 +msgid "Start docker" +msgstr "启动 docker" + +#: src/ImageSearchModal.jsx:185 +msgid "Start typing to look for images." +msgstr "开始键入来查找镜像。" + +#: src/ContainerHealthLogs.jsx:105 +msgid "Started at" +msgstr "开始于" + +#: src/Containers.jsx:569 src/ContainerDetails.jsx:67 +msgid "State" +msgstr "状态" + +#: src/ContainerHealthLogs.jsx:56 +msgid "Status" +msgstr "状态" + +#: src/PodActions.jsx:88 src/Containers.jsx:170 src/ContainerHealthLogs.jsx:41 +#: src/ImageRunModal.jsx:60 +msgid "Stop" +msgstr "停止" + +#: src/util.js:23 src/util.js:26 +msgid "Stopped" +msgstr "已停止" + +#: src/ContainerCheckpointModal.jsx:60 +msgid "Support preserving established TCP connections" +msgstr "支持保留已建立的 TCP 连接" + +#: src/PodCreateModal.jsx:164 src/ContainerHeader.jsx:20 +#: src/ImageRunModal.jsx:766 src/ImageRunModal.jsx:801 +msgid "System" +msgstr "系统" + +#: src/app.jsx:690 +msgid "System Docker service is also available" +msgstr "系统 Docker 服务同样可用" + +#: src/PublishPort.jsx:128 +msgid "TCP" +msgstr "TCP" + +#: src/ContainerCommitModal.jsx:98 src/ImageSearchModal.jsx:139 +msgid "Tag" +msgstr "标签" + +#: src/ImageDetails.jsx:27 +msgid "Tags" +msgstr "标签" + +#: org.cockpit-project.docker.metainfo.xml:10 +msgid "The Cockpit user interface for Docker containers." +msgstr "Docker 容器的 Cockpit 用户界面。" + +#: src/ImageRunModal.jsx:1086 +msgid "The initialization time needed for a container to bootstrap." +msgstr "容器进行 bootstrap 所需的初始化时间。" + +#: src/ImageRunModal.jsx:1061 +msgid "" +"The maximum time allowed to complete the health check before an interval is " +"considered failed." +msgstr "当间隔被视为失败前,允许完成健康检查的最长时间。" + +#: src/ImageRunModal.jsx:1111 +msgid "" +"The number of retries allowed before a healthcheck is considered to be " +"unhealthy." +msgstr "在健康检查被视为不健康前,允许的重试次数。" + +#: src/ContainerHealthLogs.jsx:76 src/ImageRunModal.jsx:1057 +msgid "Timeout" +msgstr "超时" + +#: src/app.jsx:649 +msgid "Troubleshoot" +msgstr "故障排除" + +#: src/ContainerHeader.jsx:28 +msgid "Type to filter…" +msgstr "输入筛选条件……" + +#: src/PublishPort.jsx:129 +msgid "UDP" +msgstr "UDP" + +#: src/ImageHistory.jsx:59 +msgid "Unable to load image history" +msgstr "无法加载镜像历史记录" + +#: src/Containers.jsx:284 +msgid "Unhealthy" +msgstr "不健康" + +#: src/ContainerDetails.jsx:12 +msgid "Up since $0" +msgstr "自 $0 开始运行" + +#: src/ContainerCommitModal.jsx:127 +msgid "Use legacy Docker format" +msgstr "使用旧的 Docker 格式" + +#: src/Images.jsx:183 src/ImageDetails.jsx:33 +msgid "Used by" +msgstr "使用者" + +#: src/app.jsx:67 src/app.jsx:528 +msgid "User" +msgstr "用户" + +#: src/app.jsx:697 +msgid "User Docker service is also available" +msgstr "用户 Docker 服务同样可用" + +#: src/PodCreateModal.jsx:169 src/ImageRunModal.jsx:783 +#: src/ImageRunModal.jsx:807 +msgid "User:" +msgstr "用户:" + +#: src/Env.jsx:72 +msgid "Value" +msgstr "值" + +#: src/PodCreateModal.jsx:190 src/ContainerIntegration.jsx:110 +#: src/ImageRunModal.jsx:1004 +msgid "Volumes" +msgstr "卷" + +#: src/ContainerHealthLogs.jsx:80 src/ImageRunModal.jsx:1130 +msgid "When unhealthy" +msgstr "当不健康时" + +#: src/ImageRunModal.jsx:880 +msgid "With terminal" +msgstr "使用终端" + +#: src/Volume.jsx:66 +msgid "Writable" +msgstr "可写入" + +#: src/manifest.json:0 +msgid "container" +msgstr "容器" + +#: src/ImageRunModal.jsx:289 +msgid "downloading" +msgstr "下载" + +#: src/ImageRunModal.jsx:820 +msgid "host[:port]/[user]/container[:tag]" +msgstr "host[:port]/[user]/container[:tag]" + +#: src/manifest.json:0 +msgid "image" +msgstr "镜像" + +#: src/ImageSearchModal.jsx:172 +msgid "in" +msgstr "于" + +#: src/ImageDeleteModal.jsx:79 +msgid "intermediate" +msgstr "中间体" + +#: src/ImageDeleteModal.jsx:59 +msgid "intermediate image" +msgstr "中间镜像" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "n/a" +msgstr "不适用" + +#: src/Containers.jsx:353 src/Containers.jsx:354 +msgid "not available" +msgstr "不可用" + +#: src/Containers.jsx:847 +msgid "pod group" +msgstr "pod 组" + +#: src/manifest.json:0 +msgid "docker" +msgstr "docker" + +#: src/Containers.jsx:532 +msgid "ports" +msgstr "端口" + +#: src/ImageRunModal.jsx:1054 src/ImageRunModal.jsx:1079 +#: src/ImageRunModal.jsx:1104 +msgid "seconds" +msgstr "秒" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 src/ImageSearchModal.jsx:160 +msgid "system" +msgstr "系统" + +#: src/Images.jsx:85 src/Images.jsx:92 +msgid "unused" +msgstr "未使用" + +#: src/PruneUnusedContainersModal.jsx:28 src/Containers.jsx:390 +#: src/Images.jsx:134 +msgid "user:" +msgstr "用户:" + +#: src/Containers.jsx:547 +msgid "volumes" +msgstr "卷" + +#~ msgid "Delete $0" +#~ msgstr "删除 $0" + +#~ msgid "select all" +#~ msgstr "全选" + +#~ msgid "Restarting" +#~ msgstr "正在重启" + +#~ msgid "Confirm deletion of $0" +#~ msgstr "确认删除 $0" + +#~ msgid "Confirm deletion of pod $0" +#~ msgstr "确认删除 pod $0" + +#~ msgid "Confirm force deletion of pod $0" +#~ msgstr "确认强制删除 pod $0" + +#~ msgid "Confirm forced deletion of $0" +#~ msgstr "确认强制删除 $0" + +#~ msgid "Container is currently running." +#~ msgstr "容器正在运行。" + +#~ msgid "Do not include root file-system changes when exporting" +#~ msgstr "导出时不包含 root 文件系统更改" + +#~ msgid "Default with single selectable" +#~ msgstr "默认使用单选" + +#~ msgid "Start after creation" +#~ msgstr "创建后启动" + +#, fuzzy +#~| msgid "Delete tagged images" +#~ msgid "Delete unused $0 images:" +#~ msgstr "删除标记的镜像" + +#~ msgid "created" +#~ msgstr "创建" + +#~ msgid "exited" +#~ msgstr "退出" + +#~ msgid "paused" +#~ msgstr "已暂停" + +#~ msgid "running" +#~ msgstr "正在运行" + +#~ msgid "stopped" +#~ msgstr "已停止" + +#, fuzzy +#~| msgid "user:" +#~ msgid "user" +#~ msgstr "用户:" + +#~ msgid "Add on build variable" +#~ msgstr "添加构建变量" + +#~ msgid "Commit image" +#~ msgstr "提交镜像" + +#~ msgid "Format" +#~ msgstr "格式" + +#~ msgid "Message" +#~ msgstr "消息" + +#~ msgid "Pause the container" +#~ msgstr "暂停该容器" + +#~ msgid "Remove on build variable" +#~ msgstr "删除构建变量" + +#~ msgid "Set container on build variables" +#~ msgstr "设置容器构建时的变量" + +#~ msgid "Add item" +#~ msgstr "添加项目" + +#~ msgid "Host port (optional)" +#~ msgstr "主机端口(可选)" + +#~ msgid "IP (optional)" +#~ msgstr "IP(可选)" + +#~ msgid "ReadOnly" +#~ msgstr "只读" + +#~ msgid "IP prefix length" +#~ msgstr "IP 前缀长度" + +#~ msgid "Get new image" +#~ msgstr "获取新镜像" + +#~ msgid "Run" +#~ msgstr "运行" + +#~ msgid "On build" +#~ msgstr "构建时" + +#~ msgid "Are you sure you want to delete this image?" +#~ msgstr "您确定要删除该镜像吗?" + +#~ msgid "Could not attach to this container: $0" +#~ msgstr "无法附加到该容器:$0" + +#~ msgid "Could not open channel: $0" +#~ msgstr "无法打开通道:$0" + +#~ msgid "Everything" +#~ msgstr "全部" + +#~ msgid "Security" +#~ msgstr "安全性" + +#~ msgid "The scan from $time ($type) found no vulnerabilities." +#~ msgstr "$time ($type) 发起的扫描未发现漏洞。" + +#~ msgid "This version of the Web Console does not support a terminal." +#~ msgstr "该版本的网页控制台不支持终端。" diff --git a/ui/cockpit-docker/pyproject.toml b/ui/cockpit-docker/pyproject.toml new file mode 100644 index 0000000..462e002 --- /dev/null +++ b/ui/cockpit-docker/pyproject.toml @@ -0,0 +1,51 @@ +[tool.ruff] +exclude = [ + ".git/", + "modules/", + "node_modules/", +] +line-length = 118 +preview = true +src = [] + +[tool.ruff.lint] +select = [ + "A", # flake8-builtins + "B", # flake8-bugbear + "C4", # flake8-comprehensions + "D300", # pydocstyle: Forbid ''' in docstrings + "DTZ", # flake8-datetimez + "E", # pycodestyle + "EXE", # flake8-executable + "F", # pyflakes + "FBT", # flake8-boolean-trap + "G", # flake8-logging-format + "I", # isort + "ICN", # flake8-import-conventions + "ISC", # flake8-implicit-str-concat + "PLE", # pylint errors + "PGH", # pygrep-hooks + "RSE", # flake8-raise + "RUF", # ruff rules + "T10", # flake8-debugger + "TCH", # flake8-type-checking + "UP032", # f-string + "W", # warnings (mostly whitespace) + "YTT", # flake8-2020 +] +ignore = [ + "FBT002", # Boolean default value in function definition + "FBT003", # Boolean positional value in function call +] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.isort] +known-first-party = ["cockpit"] + +[tool.vulture] +ignore_names = [ + "test[A-Z0-9]*", +] diff --git a/ui/cockpit-docker/src/ContainerCheckpointModal.jsx b/ui/cockpit-docker/src/ContainerCheckpointModal.jsx new file mode 100644 index 0000000..11bae17 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerCheckpointModal.jsx @@ -0,0 +1,68 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { Form } from "@patternfly/react-core/dist/esm/components/Form"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { useDialogs } from "dialogs.jsx"; +import cockpit from 'cockpit'; + +import * as client from './client.js'; + +const _ = cockpit.gettext; + +const ContainerCheckpointModal = ({ containerWillCheckpoint, onAddNotification }) => { + const Dialogs = useDialogs(); + const [inProgress, setProgress] = useState(false); + const [keep, setKeep] = useState(false); + const [leaveRunning, setLeaveRunning] = useState(false); + const [tcpEstablished, setTcpEstablished] = useState(false); + + const handleCheckpointContainer = () => { + setProgress(true); + client.postContainer("checkpoint", containerWillCheckpoint.Id, { + keep, + leaveRunning, + tcpEstablished, + }) + .catch(ex => { + const error = cockpit.format(_("Failed to checkpoint container $0"), containerWillCheckpoint.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + setProgress(false); + }) + .finally(() => { + Dialogs.close(); + }); + }; + + return ( + + + + } + > +
+ setKeep(val)} /> + setLeaveRunning(val)} /> + setTcpEstablished(val) } /> + +
+ ); +}; + +export default ContainerCheckpointModal; diff --git a/ui/cockpit-docker/src/ContainerCommitModal.jsx b/ui/cockpit-docker/src/ContainerCommitModal.jsx new file mode 100644 index 0000000..4e02100 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerCommitModal.jsx @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import cockpit from 'cockpit'; + +import { FormHelper } from 'cockpit-components-form-helper.jsx'; +import * as utils from './util.js'; +import * as client from './client.js'; +import { ErrorNotification } from './Notification.jsx'; +import { fmt_to_fragments } from 'utils.jsx'; +import { useDialogs } from "dialogs.jsx"; + +const _ = cockpit.gettext; + +const ContainerCommitModal = ({ container, localImages }) => { + const Dialogs = useDialogs(); + + const [imageName, setImageName] = useState(""); + const [tag, setTag] = useState(""); + const [author, setAuthor] = useState(""); + const [command, setCommand] = useState(utils.quote_cmdline(container.Config.Cmd)); + const [pause, setPause] = useState(false); + + const [dialogError, setDialogError] = useState(""); + const [dialogErrorDetail, setDialogErrorDetail] = useState(""); + const [commitInProgress, setCommitInProgress] = useState(false); + const [nameError, setNameError] = useState(""); + + const handleCommit = (force) => { + if (!force && !imageName) { + setNameError(_("Image name is required")); + return; + } + + let full_name = imageName + ":" + (tag !== "" ? tag : "latest"); + if (full_name.indexOf("/") < 0) + full_name = "localhost/" + full_name; + + if (!force && localImages.some(image => image.Name === full_name)) { + setNameError(_("Image name is not unique")); + return; + } + + function quote(word) { + word = word.replace(/"/g, '\\"'); + return '"' + word + '"'; + } + + const commitData = {}; + commitData.container = container.Id; + commitData.repo = imageName; + commitData.author = author; + commitData.pause = pause; + commitData.format = 'docker'; + + if (tag) + commitData.tag = tag; + + commitData.changes = []; + if (command.trim() !== "") { + let cmdData = ""; + const words = utils.unquote_cmdline(command.trim()); + const cmdStr = words.map(quote).join(", "); + cmdData = "CMD [" + cmdStr + "]"; + commitData.changes.push(cmdData); + } + + setCommitInProgress(true); + setNameError(""); + setDialogError(""); + setDialogErrorDetail(""); + client.commitContainer(commitData) + .then(() => Dialogs.close()) + .catch(ex => { + setDialogError(cockpit.format(_("Failed to commit container $0"), container.Name)); + setDialogErrorDetail(cockpit.format("$0: $1", ex.message, ex.reason)); + setCommitInProgress(false); + }); + }; + + const commitContent = ( +
+ {dialogError && setDialogError("")} />} + + { setNameError(""); setImageName(value) }} /> + + + + + { setNameError(""); setTag(value) }} /> + + + + ")} + value={author} + onChange={(_, value) => setAuthor(value)} /> + + + + setCommand(value)} /> + + + + setPause(val)} + label={_("Pause container when creating image")} /> + + + ); + + return ( + {container.Name})} + footer={<> + + {nameError && } + + } + > + {commitContent} + + ); +}; + +export default ContainerCommitModal; diff --git a/ui/cockpit-docker/src/ContainerDeleteModal.jsx b/ui/cockpit-docker/src/ContainerDeleteModal.jsx new file mode 100644 index 0000000..ce2087d --- /dev/null +++ b/ui/cockpit-docker/src/ContainerDeleteModal.jsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { useDialogs } from "dialogs.jsx"; +import cockpit from 'cockpit'; + +import * as client from './client.js'; + +const _ = cockpit.gettext; + +const ContainerDeleteModal = ({ containerWillDelete, onAddNotification }) => { + const Dialogs = useDialogs(); + + const handleRemoveContainer = () => { + const container = containerWillDelete; + const id = container ? container.Id : ""; + + Dialogs.close(); + client.delContainer(id, false) + .catch(ex => { + const error = cockpit.format(_("Failed to remove container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + return ( + + {' '} + + } + > + {_("Deleting a container will erase all data in it.")} + + ); +}; + +export default ContainerDeleteModal; diff --git a/ui/cockpit-docker/src/ContainerDetails.jsx b/ui/cockpit-docker/src/ContainerDetails.jsx new file mode 100644 index 0000000..96549ae --- /dev/null +++ b/ui/cockpit-docker/src/ContainerDetails.jsx @@ -0,0 +1,80 @@ +import React from 'react'; +import cockpit from 'cockpit'; +import * as utils from './util.js'; + +import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex"; + +const _ = cockpit.gettext; + +const render_container_state = (container) => { + if (container.State.Status === "running") { + return cockpit.format(_("Up since $0"), utils.localize_time(Date.parse(container.State.StartedAt) / 1000)); + } + return cockpit.format(_("Exited")); +}; + +const ContainerDetails = ({ container }) => { + const networkOptions = ( + [ + container.NetworkSettings?.IPAddress, + container.NetworkSettings?.Gateway, + container.NetworkSettings?.MacAddress, + ].some(itm => !!itm) + ); + + return ( + + + + + {_("ID")} + {utils.truncate_id(container.Id)} + + + {_("Image")} + {container.Config.Image} + + + {_("Command")} + {utils.quote_cmdline(container.Config?.Cmd)} + + + + + {networkOptions && + {container.NetworkSettings?.IPAddress && + {_("IP address")} + {container.NetworkSettings.IPAddress} + } + {container.NetworkSettings?.Gateway && + {_("Gateway")} + {container.NetworkSettings.Gateway} + } + {container.NetworkSettings?.MacAddress && + {_("MAC address")} + {container.NetworkSettings.MacAddress} + } + } + + + + + {_("Created")} + {utils.localize_time(new Date(container.Created) / 1000)} + + + {_("State")} + {render_container_state(container)} + + {container.State?.Checkpointed && + {_("Latest checkpoint")} + {utils.localize_time(Date.parse(container.State.CheckpointedAt) / 1000)} + } + + + + ); +}; + +export default ContainerDetails; diff --git a/ui/cockpit-docker/src/ContainerHeader.jsx b/ui/cockpit-docker/src/ContainerHeader.jsx new file mode 100644 index 0000000..f7ecacc --- /dev/null +++ b/ui/cockpit-docker/src/ContainerHeader.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import cockpit from 'cockpit'; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import { Toolbar, ToolbarContent, ToolbarItem } from "@patternfly/react-core/dist/esm/components/Toolbar"; +const _ = cockpit.gettext; + +const ContainerHeader = ({ textFilter, handleFilterChanged }) => { + return ( + + + + handleFilterChanged(value)} /> + + + + ); +}; + +export default ContainerHeader; diff --git a/ui/cockpit-docker/src/ContainerHealthLogs.jsx b/ui/cockpit-docker/src/ContainerHealthLogs.jsx new file mode 100644 index 0000000..1d9b354 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerHealthLogs.jsx @@ -0,0 +1,158 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2022 Red Hat, Inc and 2023 Jewish Education Media. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import React from 'react'; +import cockpit from 'cockpit'; +import * as utils from './util.js'; + +import { ListingTable } from "cockpit-components-table.jsx"; +import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { CheckCircleIcon, ErrorCircleOIcon } from "@patternfly/react-icons"; +import { CodeBlock, CodeBlockAction, CodeBlockCode } from '@patternfly/react-core/dist/esm/components/CodeBlock'; +import { ClipboardCopyButton } from '@patternfly/react-core/dist/esm/components/ClipboardCopy'; +import { ExpandableSection, ExpandableSectionToggle } from '@patternfly/react-core/dist/esm/components/ExpandableSection'; +const _ = cockpit.gettext; + +const format_nanoseconds = (ns) => { + const seconds = ns / 1000000000; + return cockpit.format(cockpit.ngettext("$0 second", "$0 seconds", seconds), seconds); +}; + +const HealthcheckOnFailureActionText = { + none: _("No action"), + restart: _("Restart"), + stop: _("Stop"), + kill: _("Force stop"), +}; + +const HealthLogBlock = ({ log }) => { + const [expanded, setExpanded] = React.useState(false); + const toggleExpanded = () => setExpanded(!expanded); + + const actions = ( + <> + + + + + ); + + let output = log.Output.split("\n"); + let extra = null; + if (output.length > 10) { + extra = output.slice(10).join("\n"); + output = output.slice(0, 10).join("\n"); + } else { + output = output.join("\n"); + } + + return ( + + + {output} + {extra && + {extra} + } + + { extra && + {expanded ? 'Show Less' : 'Show More'} + } + + ); +}; + +const ContainerHealthLogs = ({ container, onAddNotification, state }) => { + const healthCheck = container.Config?.Healthcheck ?? container.Config?.Health ?? {}; // not-covered: only on old version + const healthState = container.State?.Healthcheck ?? container.State?.Health ?? {}; // not-covered: only on old version + const logs = [...(healthState.Log || [])].reverse(); // not-covered: Log should always exist, belt-and-suspenders + + return ( + <> + + + + + {_("Status")} + {state} + + + {_("Command")} + {utils.quote_cmdline(healthCheck.Test)} + + {healthCheck.Interval && + {_("Interval")} + {format_nanoseconds(healthCheck.Interval)} + } + {healthCheck.Retries && + {_("Retries")} + {healthCheck.Retries} + } + {healthCheck.StartPeriod && + {_("Start period")} + {format_nanoseconds(healthCheck.StartPeriod)} + } + {healthCheck.Timeout && + {_("Timeout")} + {format_nanoseconds(healthCheck.Timeout)} + } + {container.Config?.HealthcheckOnFailureAction && + {_("When unhealthy")} + {HealthcheckOnFailureActionText[container.Config.HealthcheckOnFailureAction]} + } + {healthState.FailingStreak && + {_("Failing streak")} + {healthState.FailingStreak} + } + + + + { + const id = "hc" + log.Start + container.Id; + return { + expandedContent: log.Output ? : null, + columns: [ + { + title: + {log.ExitCode === 0 ? : } + {log.ExitCode === 0 ? _("Passed health run") : _("Failed health run")} + + }, + { + title:
{log.ExitCode}
+ }, + utils.localize_time(Date.parse(log.Start) / 1000) + ], + props: { + key: id, + "data-row-id": id, + }, + }; + }) + } /> + + ); +}; + +export default ContainerHealthLogs; diff --git a/ui/cockpit-docker/src/ContainerIntegration.jsx b/ui/cockpit-docker/src/ContainerIntegration.jsx new file mode 100644 index 0000000..999bead --- /dev/null +++ b/ui/cockpit-docker/src/ContainerIntegration.jsx @@ -0,0 +1,125 @@ +import React, { useState } from 'react'; +import cockpit from 'cockpit'; + +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList"; +import { List, ListItem } from "@patternfly/react-core/dist/esm/components/List"; +import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip"; + +import { EmptyStatePanel } from "cockpit-components-empty-state.jsx"; + +const _ = cockpit.gettext; + +// ports is a mapping like { "5000/tcp": [{"HostIp": "", "HostPort": "6000"}] } +export const renderContainerPublishedPorts = ports => { + if (!ports) + return null; + + const items = []; + Object.entries(ports).forEach(([containerPort, hostBindings]) => { + (hostBindings ?? []).forEach(binding => { // not-covered: null was observed in the wild, but unknown how to reproduce + items.push( + + { binding.HostIp || "0.0.0.0" }:{ binding.HostPort } → { containerPort } + + ); + }); + }); + + return {items}; +}; + +export const renderContainerVolumes = (volumes) => { + if (!volumes.length) + return null; + + const result = volumes.map(volume => { + let source = volume.Source; + if (volume.Source.includes(`docker/volumes/${volume.Name}`)) { + source = volume.Name; + } + return ( + + {source} + {volume.RW + ? + : } + {volume.Destination} + + ); + }); + + return {result}; +}; + +const ContainerEnv = ({ containerEnv, imageEnv }) => { + // filter out some Environment variables set by docker or by image + const toRemoveEnv = [...imageEnv, 'container=docker']; + let toShow = containerEnv.filter(variable => { + if (toRemoveEnv.includes(variable)) { + return false; + } + + return !variable.match(/(HOME|TERM)=.*/); + }); + + // append filtered out variables to always shown variables when 'show more' is clicked + const [showMore, setShowMore] = useState(false); + if (showMore) + toShow = toShow.concat(containerEnv.filter(variable => !toShow.includes(variable))); + + if (!toShow.length) + return null; + + const result = toShow.map(variable => { + return ( + + {variable} + + ); + }); + + result.push( + + + + ); + + return {result}; +}; + +const ContainerIntegration = ({ container, localImages }) => { + if (localImages === null) { // not-covered: not a stable UI state + return ( + + ); + } + + const ports = renderContainerPublishedPorts(container.NetworkSettings.Ports); + const volumes = renderContainerVolumes(container.Mounts); + + const image = localImages.filter(img => img.Id === container.Image)[0]; + const env = ; + + return ( + + {ports && + {_("Ports")} + {ports} + } + {volumes && + {_("Volumes")} + {volumes} + } + {env && + {_("Environment variables")} + {env} + } + + ); +}; + +export default ContainerIntegration; diff --git a/ui/cockpit-docker/src/ContainerLogs.jsx b/ui/cockpit-docker/src/ContainerLogs.jsx new file mode 100644 index 0000000..7bcf0a7 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerLogs.jsx @@ -0,0 +1,174 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2020 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { Terminal } from "xterm"; +import { CanvasAddon } from 'xterm-addon-canvas'; +import { ExclamationCircleIcon } from '@patternfly/react-icons'; + +import cockpit from 'cockpit'; +import rest from './rest.js'; +import * as client from './client.js'; +import { EmptyStatePanel } from "cockpit-components-empty-state.jsx"; + +import "./ContainerTerminal.css"; + +const _ = cockpit.gettext; + +class ContainerLogs extends React.Component { + constructor(props) { + super(props); + + this.onStreamClose = this.onStreamClose.bind(this); + this.onStreamMessage = this.onStreamMessage.bind(this); + this.connectStream = this.connectStream.bind(this); + + this.view = new Terminal({ + cols: 80, + rows: 24, + convertEol: true, + cursorBlink: false, + disableStdin: true, + fontSize: 12, + fontFamily: 'Menlo, Monaco, Consolas, monospace', + screenReaderMode: true + }); + this.view._core.cursorHidden = true; + this.view.write(_("Loading logs...")); + + this.logRef = React.createRef(); + + this.state = { + opened: false, + loading: true, + errorMessage: "", + streamer: null, + }; + } + + componentDidMount() { + this._ismounted = true; + this.connectStream(); + } + + componentDidUpdate(prevProps, prevState) { + // Connect channel when there is none and container started + if (!this.state.streamer && this.props.containerStatus === "running" && prevProps.containerStatus !== "running") + this.connectStream(); + if (prevProps.width !== this.props.width) { + this.resize(this.props.width); + } + } + + resize(width) { + // 24 PF padding * 4 + // 3 line border + // 21 inner padding of xterm.js + // xterm.js scrollbar 20 + const padding = 24 * 4 + 3 + 21 + 20; + const realWidth = this.view._core._renderService.dimensions.css.cell.width; + const cols = Math.floor((width - padding) / realWidth); + this.view.resize(cols, 24); + } + + componentWillUnmount() { + this._ismounted = false; + if (this.state.streamer) + this.state.streamer.close(); + this.view.dispose(); + } + + connectStream() { + if (this.state.streamer !== null) + return; + + // Show the terminal. Once it was shown, do not show it again but reuse the previous one + if (!this.state.opened) { + this.view.open(this.logRef.current); + this.view.loadAddon(new CanvasAddon()); + this.setState({ opened: true }); + } + this.resize(this.props.width); + + const connection = rest.connect(client.getAddress()); + const options = { + method: "GET", + path: client.VERSION + "/containers/" + this.props.containerId + "/logs", + body: "", + binary: true, + params: { + follow: true, + stdout: true, + stderr: true, + }, + }; + + connection.monitor(options, this.onStreamMessage, true) + .then(this.onStreamClose) + .catch(e => { + const error = JSON.parse(new TextDecoder().decode(e.message)); + this.setState({ + errorMessage: error.message, + streamer: null, + }); + }); + this.setState({ + streamer: connection, + errorMessage: "", + }); + } + + onStreamMessage(data) { + if (data) { + if (this.state.loading) { + this.view.reset(); + this.view._core.cursorHidden = true; + this.setState({ loading: false }); + } + // First 8 bytes encode information about stream and frame + // See 'Stream format' on https://docs.docker.com/engine/api/v1.40/#operation/ContainerAttach + this.view.writeln(data.slice(8)); + } + } + + onStreamClose() { + if (this._ismounted) { + this.setState({ + streamer: null, + }); + this.view.write("Streaming disconnected"); + } + } + + render() { + let element =
; + if (this.state.errorMessage) + element = ; + + return element; + } +} + +ContainerLogs.propTypes = { + containerId: PropTypes.string.isRequired, + width: PropTypes.number.isRequired +}; + +export default ContainerLogs; diff --git a/ui/cockpit-docker/src/ContainerRenameModal.jsx b/ui/cockpit-docker/src/ContainerRenameModal.jsx new file mode 100644 index 0000000..c81c0f2 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerRenameModal.jsx @@ -0,0 +1,107 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import cockpit from 'cockpit'; + +import * as client from './client.js'; +import * as utils from './util.js'; +import { ErrorNotification } from './Notification.jsx'; +import { useDialogs } from "dialogs.jsx"; +import { FormHelper } from 'cockpit-components-form-helper.jsx'; + +const _ = cockpit.gettext; + +const ContainerRenameModal = ({ container, updateContainer }) => { + const Dialogs = useDialogs(); + const [name, setName] = useState(container.Name.replace(/^\//, "")); + const { version } = utils.useDockerInfo(); + const [nameError, setNameError] = useState(null); + const [dialogError, setDialogError] = useState(null); + const [dialogErrorDetail, setDialogErrorDetail] = useState(null); + + const handleInputChange = (targetName, value) => { + if (targetName === "name") { + setName(value); + if (value === "") { + setNameError(_("Container name is required.")); + } else if (utils.is_valid_container_name(value)) { + setNameError(null); + } else { + setNameError(_("Invalid characters. Name can only contain letters, numbers, and certain punctuation (_ . -).")); + } + } + }; + + const handleRename = () => { + if (!name) { + setNameError(_("Container name is required.")); + return; + } + + setNameError(null); + setDialogError(null); + client.renameContainer(container.Id, { name }) + .then(() => { + Dialogs.close(); + // HACK: This is a workaround for missing API rename event in docker versions less than 4.1. + if (version.localeCompare("4.1", undefined, { numeric: true, sensitivity: 'base' }) < 0) { + updateContainer(container.Id); // not-covered: only on old version + } + }) + .catch(ex => { + setDialogError(cockpit.format(_("Failed to rename container $0"), container.Name)); // not-covered: OS error + setDialogErrorDetail(cockpit.format("$0: $1", ex.message, ex.reason)); + }); + }; + + const handleKeyDown = (event) => { + if (event.key === "Enter") { + event.preventDefault(); + handleRename(); + } + }; + + const renameContent = ( +
+ + handleInputChange("name", value)} /> + + +
+ ); + + return ( + + + + } + > + {dialogError && setDialogError(null)} />} + {renameContent} + + ); +}; + +export default ContainerRenameModal; diff --git a/ui/cockpit-docker/src/ContainerRestoreModal.jsx b/ui/cockpit-docker/src/ContainerRestoreModal.jsx new file mode 100644 index 0000000..c3575bb --- /dev/null +++ b/ui/cockpit-docker/src/ContainerRestoreModal.jsx @@ -0,0 +1,74 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { Form } from "@patternfly/react-core/dist/esm/components/Form"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { useDialogs } from "dialogs.jsx"; +import cockpit from 'cockpit'; + +import * as client from './client.js'; + +const _ = cockpit.gettext; + +const ContainerRestoreModal = ({ containerWillRestore, onAddNotification }) => { + const Dialogs = useDialogs(); + + const [inProgress, setInProgress] = useState(false); + const [keep, setKeep] = useState(false); + const [tcpEstablished, setTcpEstablished] = useState(false); + const [ignoreStaticIP, setIgnoreStaticIP] = useState(false); + const [ignoreStaticMAC, setIgnoreStaticMAC] = useState(false); + + const handleRestoreContainer = () => { + setInProgress(true); + client.postContainer("restore", containerWillRestore.Id, { + keep, + tcpEstablished, + ignoreStaticIP, + ignoreStaticMAC, + }) + .catch(ex => { + const error = cockpit.format(_("Failed to restore container $0"), containerWillRestore.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + setInProgress(false); + }) + .finally(() => { + Dialogs.close(); + }); + }; + + return ( + + + + } + > +
+ setKeep(val)} /> + setTcpEstablished(val)} /> + setIgnoreStaticIP(val)} /> + setIgnoreStaticMAC(val)} /> + +
+ ); +}; + +export default ContainerRestoreModal; diff --git a/ui/cockpit-docker/src/ContainerTerminal.css b/ui/cockpit-docker/src/ContainerTerminal.css new file mode 100644 index 0000000..27d2f5b --- /dev/null +++ b/ui/cockpit-docker/src/ContainerTerminal.css @@ -0,0 +1,7 @@ +@import "xterm/css/xterm.css"; + +.terminal { + /* 5px all around and on right +11 since the scrollbar is 11px wide */ + padding-block: 5px; + padding-inline: 5px 16px; +} diff --git a/ui/cockpit-docker/src/ContainerTerminal.jsx b/ui/cockpit-docker/src/ContainerTerminal.jsx new file mode 100644 index 0000000..8840456 --- /dev/null +++ b/ui/cockpit-docker/src/ContainerTerminal.jsx @@ -0,0 +1,265 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2019 Red Hat, Inc and 2023 Jewish Education Media. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import cockpit from 'cockpit'; +import { Terminal } from "xterm"; +import { CanvasAddon } from 'xterm-addon-canvas'; +import { ErrorNotification } from './Notification.jsx'; + +import * as client from './client.js'; +import { EmptyStatePanel } from "cockpit-components-empty-state.jsx"; + +import "./ContainerTerminal.css"; + +const _ = cockpit.gettext; +const decoder = cockpit.utf8_decoder(); +const encoder = cockpit.utf8_encoder(); + +function sequence_find(seq, find) { + let f; + const fl = find.length; + let s; + const sl = (seq.length - fl) + 1; + for (s = 0; s < sl; s++) { + for (f = 0; f < fl; f++) { + if (seq[s + f] !== find[f]) + break; + } + if (f == fl) + return s; + } + + return -1; +} + +class ContainerTerminal extends React.Component { + constructor(props) { + super(props); + + this.onChannelClose = this.onChannelClose.bind(this); + this.onChannelMessage = this.onChannelMessage.bind(this); + this.disconnectChannel = this.disconnectChannel.bind(this); + this.connectChannel = this.connectChannel.bind(this); + this.resize = this.resize.bind(this); + this.connectToTty = this.connectToTty.bind(this); + this.execAndConnect = this.execAndConnect.bind(this); + this.setUpBuffer = this.setUpBuffer.bind(this); + + this.terminalRef = React.createRef(); + + this.term = new Terminal({ + cols: 80, + rows: 24, + screenKeys: true, + cursorBlink: true, + fontSize: 12, + fontFamily: 'Menlo, Monaco, Consolas, monospace', + screenReaderMode: true + }); + + this.state = { + container: props.containerId, + sessionId: props.containerId, + channel: null, + buffer: null, + opened: false, + errorMessage: "", + }; + } + + componentDidMount() { + this.connectChannel(); + } + + componentDidUpdate(prevProps, prevState) { + // Connect channel when there is none and either container started or tty was resolved + if (!this.state.channel && ( + (this.props.containerStatus === "running" && prevProps.containerStatus !== "running") || + (this.props.tty !== undefined && prevProps.tty === undefined))) + this.connectChannel(); + if (prevProps.width !== this.props.width) { + this.resize(this.props.width); + } + } + + resize(width) { + // 24 PF padding * 4 + // 3 line border + // 21 inner padding of xterm.js + // xterm.js scrollbar 20 + const padding = 24 * 4 + 3 + 21 + 20; + const realWidth = this.term._core._renderService.dimensions.css.cell.width; + const cols = Math.floor((width - padding) / realWidth); + this.term.resize(cols, 24); + client.resizeContainersTTY(this.state.sessionId, this.props.tty, cols, 24) + .catch(e => this.setState({ errorMessage: e.message })); + } + + connectChannel() { + if (this.state.channel) + return; + + if (this.props.containerStatus !== "running") + return; + + if (this.props.tty === undefined) + return; + + if (this.props.tty) + this.connectToTty(); + else + this.execAndConnect(); + } + + setUpBuffer(channel) { + const buffer = channel.buffer(); + + // Parse the full HTTP response + buffer.callback = (data) => { + let ret = 0; + let pos = 0; + // let headers = ""; + + // Double line break separates header from body + pos = sequence_find(data, [13, 10, 13, 10]); + if (pos == -1) + return ret; + + if (data.subarray) { + data = data.subarray(pos + 4); + ret += pos + 4; + } else { + data = data.slice(pos + 4); + ret += pos + 4; + } + // Set up callback for new incoming messages and if the first response + // contained any body, pass it into the callback + buffer.callback = this.onChannelMessage; + const consumed = this.onChannelMessage(data); + return ret + consumed; + }; + + channel.addEventListener('close', this.onChannelClose); + + // Show the terminal. Once it was shown, do not show it again but reuse the previous one + if (!this.state.opened) { + this.term.open(this.terminalRef.current); + this.term.loadAddon(new CanvasAddon()); + this.setState({ opened: true }); + + this.term.onData((data) => { + if (this.state.channel) + this.state.channel.send(encoder.encode(data)); + }); + } + channel.send(String.fromCharCode(12)); // Send SIGWINCH to show prompt on attaching + + return buffer; + } + + execAndConnect() { + client.execContainer(this.state.container) + .then(r => { + const channel = cockpit.channel({ + payload: "stream", + unix: client.getAddress(), + binary: true + }); + + const body = JSON.stringify({ Detach: false, Tty: false }); + channel.send("POST " + client.VERSION + "/exec/" + encodeURIComponent(r.Id) + + "/start HTTP/1.0\r\n" + + "Content-Type: application/json; charset=utf-8\r\n" + + "Content-Length: " + body.length + "\r\n\r\n" + body); + + const buffer = this.setUpBuffer(channel); + this.setState({ channel, errorMessage: "", buffer, sessionId: r.Id }, () => { console.log(this.props.width); this.resize(this.props.width) }); + }) + .catch(e => this.setState({ errorMessage: e.message })); + } + + connectToTty() { + const channel = cockpit.channel({ + payload: "stream", + unix: client.getAddress(), + binary: true + }); + + channel.send("POST " + client.VERSION + "/containers/" + encodeURIComponent(this.state.container) + + "/attach?stdin=true&stdout=true&stderr=true&stream=true HTTP/1.0\r\n" + + "Upgrade: tcp\r\nConnection: Upgrade\r\n\r\n"); + + const buffer = this.setUpBuffer(channel); + this.setState({ channel, errorMessage: "", buffer }); + this.resize(this.props.width); + } + + componentWillUnmount() { + this.disconnectChannel(); + if (this.state.channel) + this.state.channel.close(); + this.term.dispose(); + } + + onChannelMessage(buffer) { + if (buffer) + this.term.write(decoder.decode(buffer)); + return buffer.length; + } + + onChannelClose(event, options) { + this.term.write('\x1b[31m disconnected \x1b[m\r\n'); + this.disconnectChannel(); + this.setState({ channel: null }); + this.term.cursorHidden = true; + } + + disconnectChannel() { + if (this.state.buffer) + this.state.buffer.callback = null; // eslint-disable-line react/no-direct-mutation-state + if (this.state.channel) { + this.state.channel.removeEventListener('close', this.onChannelClose); + } + } + + render() { + let element =
; + + if (this.props.containerStatus !== "running" && !this.state.opened) + element = ; + + return ( + <> + {this.state.errorMessage && this.setState({ errorMessage: "" })} />} + {element} + + ); + } +} + +ContainerTerminal.propTypes = { + containerId: PropTypes.string.isRequired, + containerStatus: PropTypes.string.isRequired, + width: PropTypes.number.isRequired, + tty: PropTypes.bool, +}; + +export default ContainerTerminal; diff --git a/ui/cockpit-docker/src/Containers.jsx b/ui/cockpit-docker/src/Containers.jsx new file mode 100644 index 0000000..b9a0cf2 --- /dev/null +++ b/ui/cockpit-docker/src/Containers.jsx @@ -0,0 +1,611 @@ +import React from 'react'; +import { Badge } from "@patternfly/react-core/dist/esm/components/Badge"; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Card, CardBody, CardHeader, CardTitle } from "@patternfly/react-core/dist/esm/components/Card"; +import { Divider } from "@patternfly/react-core/dist/esm/components/Divider"; +import { DropdownItem } from '@patternfly/react-core/dist/esm/components/Dropdown/index.js'; +import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { LabelGroup } from "@patternfly/react-core/dist/esm/components/Label"; +import { Text, TextVariants } from "@patternfly/react-core/dist/esm/components/Text"; +import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect"; +import { Toolbar, ToolbarContent, ToolbarItem } from "@patternfly/react-core/dist/esm/components/Toolbar"; +import { cellWidth, SortByDirection } from '@patternfly/react-table'; + +import cockpit from 'cockpit'; +import { ListingTable } from "cockpit-components-table.jsx"; +import { ListingPanel } from 'cockpit-components-listing-panel.jsx'; +import ContainerDetails from './ContainerDetails.jsx'; +import ContainerIntegration from './ContainerIntegration.jsx'; +import ContainerTerminal from './ContainerTerminal.jsx'; +import ContainerLogs from './ContainerLogs.jsx'; +import ContainerHealthLogs from './ContainerHealthLogs.jsx'; +import ContainerDeleteModal from './ContainerDeleteModal.jsx'; +import ForceRemoveModal from './ForceRemoveModal.jsx'; +import * as utils from './util.js'; +import * as client from './client.js'; +import ContainerCommitModal from './ContainerCommitModal.jsx'; +import ContainerRenameModal from './ContainerRenameModal.jsx'; +import { useDialogs, DialogsContext } from "dialogs.jsx"; + +import './Containers.scss'; +import '@patternfly/patternfly/utilities/Accessibility/accessibility.css'; +import { ImageRunModal } from './ImageRunModal.jsx'; +import PruneUnusedContainersModal from './PruneUnusedContainersModal.jsx'; + +import { KebabDropdown } from "cockpit-components-dropdown.jsx"; + +const _ = cockpit.gettext; + +const ContainerActions = ({ container, healthcheck, onAddNotification, localImages, updateContainer }) => { + const Dialogs = useDialogs(); + const { version } = utils.useDockerInfo(); + const isRunning = container.State.Status === "running"; + const isPaused = container.State.Status === "paused"; + const isRestarting = container.State.Status === "restarting"; + + const deleteContainer = (event) => { + if (container.State.Status == "running") { + const handleForceRemoveContainer = () => { + const id = container ? container.Id : ""; + + return client.delContainer(id, true) + .catch(ex => { + const error = cockpit.format(_("Failed to force remove container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + throw ex; + }) + .finally(() => { + Dialogs.close(); + }); + }; + + Dialogs.show(); + } else { + Dialogs.show(); + } + }; + + const stopContainer = (force) => { + const args = {}; + + if (force) + args.t = 0; + client.postContainer("stop", container.Id, args) + .catch(ex => { + const error = cockpit.format(_("Failed to stop container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + const startContainer = () => { + client.postContainer("start", container.Id, {}) + .catch(ex => { + const error = cockpit.format(_("Failed to start container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + const resumeContainer = () => { + client.postContainer("unpause", container.Id, {}) + .catch(ex => { + const error = cockpit.format(_("Failed to resume container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + const pauseContainer = () => { + client.postContainer("pause", container.Id, {}) + .catch(ex => { + const error = cockpit.format(_("Failed to pause container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + const commitContainer = () => { + Dialogs.show(); + }; + + const restartContainer = (force) => { + const args = {}; + + if (force) + args.t = 0; + client.postContainer("restart", container.Id, args) + .catch(ex => { + const error = cockpit.format(_("Failed to restart container $0"), container.Name); // not-covered: OS error + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + }; + + const renameContainer = () => { + if (container.State.Status !== "running" || + version.localeCompare("3.0.1", undefined, { numeric: true, sensitivity: 'base' }) >= 0) { + Dialogs.show(); + } + }; + + const addRenameAction = () => { + actions.push( + renameContainer()}> + {_("Rename")} + + ); + }; + + const actions = []; + if (isRunning || isPaused || isRestarting) { + actions.push( + stopContainer()}> + {_("Stop")} + , + stopContainer(true)}> + {_("Force stop")} + , + restartContainer()}> + {_("Restart")} + , + restartContainer(true)}> + {_("Force restart")} + + ); + + if (!isPaused) { + actions.push( + pauseContainer()}> + {_("Pause")} + + ); + } else { + actions.push( + resumeContainer()}> + {_("Resume")} + + ); + } + } + + if (!isRunning && !isPaused) { + actions.push( + startContainer()}> + {_("Start")} + + ); + actions.push(); + if (version.localeCompare("3", undefined, { numeric: true, sensitivity: 'base' }) >= 0) { + addRenameAction(); + } + } else { // running or paused + actions.push(); + if (version.localeCompare("3.0.1", undefined, { numeric: true, sensitivity: 'base' }) >= 0) { + addRenameAction(); + } + } + + actions.push(); + actions.push( + commitContainer()}> + {_("Commit")} + + ); + + actions.push(); + actions.push( + + {_("Delete")} + + ); + + return ; +}; + +export let onDownloadContainer = function funcOnDownloadContainer(container) { + this.setState(prevState => ({ + downloadingContainers: [...prevState.downloadingContainers, container] + })); +}; + +export let onDownloadContainerFinished = function funcOnDownloadContainerFinished(container) { + this.setState(prevState => ({ + downloadingContainers: prevState.downloadingContainers.filter(entry => entry.name !== container.name), + })); +}; + +const localize_health = (state) => { + if (state === "healthy") + return _("Healthy"); + else if (state === "unhealthy") + return _("Unhealthy"); + else if (state === "starting") + return _("Checking health"); + else + console.error("Unexpected health check status", state); + return null; +}; + +const ContainerOverActions = ({ handlePruneUnusedContainers, unusedContainers }) => { + const actions = [ + handlePruneUnusedContainers()} + isDisabled={unusedContainers.length === 0}> + {_("Prune unused containers")} + , + ]; + + return ; +}; + +class Containers extends React.Component { + static contextType = DialogsContext; + + constructor(props) { + super(props); + this.state = { + width: 0, + downloadingContainers: [], + showPruneUnusedContainersModal: false, + }; + this.renderRow = this.renderRow.bind(this); + this.onWindowResize = this.onWindowResize.bind(this); + + this.cardRef = React.createRef(); + + onDownloadContainer = onDownloadContainer.bind(this); + onDownloadContainerFinished = onDownloadContainerFinished.bind(this); + + window.addEventListener('resize', this.onWindowResize); + } + + componentDidMount() { + this.onWindowResize(); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.onWindowResize); + } + + renderRow(containersStats, container, localImages) { + const containerStats = containersStats[container.Id]; + // if (containerStats?.name === "/build-jaeger-1") { + // console.log(container); + // console.log(containerStats); + // } + const image = container.Config?.Image || container.Image; + const isToolboxContainer = container.Config?.Labels?.["com.github.containers.toolbox"] === "true"; + const isDistroboxContainer = container.Config?.Labels?.manager === "distrobox"; + let localized_health = null; + + // this needs to get along with stub containers from image run dialog, where most properties don't exist yet + const healthcheck = container.State?.Health?.Status ?? container.State?.Healthcheck?.Status; // not-covered: only on old version + const status = container.State?.Status ?? ""; // not-covered: race condition + + let proc_text = ""; + let mem_text = ""; + let proc = 0; + let mem = 0; + if (this.props.cgroupVersion === 'v1' && status === 'running') { // not-covered: only on old version + proc_text =
{_("n/a")}
; + mem_text =
{_("n/a")}
; + } + if (containerStats && status === "running") { + [proc_text, proc] = utils.format_cpu_usage(containerStats); + [mem_text, mem] = utils.format_memory_and_limit(containerStats); + } + + const info_block = ( +
+ + {container.Name} + {isToolboxContainer && toolbox} + {isDistroboxContainer && distrobox} + + {image.includes("sha256:") ? utils.truncate_id(image) : image} + {utils.quote_cmdline(container.Config?.Cmd)} +
+ ); + + let containerStateClass = "ct-badge-container-" + status.toLowerCase(); + if (container.isDownloading) + containerStateClass += " downloading"; + + const containerState = status.charAt(0).toUpperCase() + status.slice(1); + + const state = [{_(containerState)}]; // States are defined in util.js + if (healthcheck) { + localized_health = localize_health(healthcheck); + if (localized_health) + state.push({localized_health}); + } + + const columns = [ + { title: info_block, sortKey: container.Name }, + { title: proc_text, props: { modifier: "nowrap" }, sortKey: containerState === "Running" ? proc ?? -1 : -1 }, + { title: mem_text, props: { modifier: "nowrap" }, sortKey: mem ?? -1 }, + { title: {state}, sortKey: containerState }, + ]; + + if (!container.isDownloading) { + columns.push({ + title: , + props: { className: "pf-v5-c-table__action" } + }); + } + + const tty = !!container.Config?.Tty; + + const tabs = []; + if (container.State) { + tabs.push({ + name: _("Details"), + renderer: ContainerDetails, + data: { container } + }); + + if (!container.isDownloading) { + tabs.push({ + name: _("Integration"), + renderer: ContainerIntegration, + data: { container, localImages } + }); + tabs.push({ + name: _("Logs"), + renderer: ContainerLogs, + data: { containerId: container.Id, containerStatus: container.State.Status, width: this.state.width } + }); + tabs.push({ + name: _("Console"), + renderer: ContainerTerminal, + data: { containerId: container.Id, containerStatus: container.State?.Status, width: this.state.width, tty } + }); + } + } + + if (healthcheck) { + tabs.push({ + name: _("Health check"), + renderer: ContainerHealthLogs, + data: { container, onAddNotification: this.props.onAddNotification, state: localized_health } + }); + } + + return { + expandedContent: , + columns, + initiallyExpanded: document.location.hash.substr(1) === container.Id, + props: { + key: container.Id, + "data-row-id": container.Id, + "data-started-at": container.StartedAt, + }, + }; + } + + onWindowResize() { + this.setState({ width: this.cardRef.current.clientWidth }); + } + + onOpenPruneUnusedContainersDialog = () => { + this.setState({ showPruneUnusedContainersModal: true }); + }; + + render() { + const Dialogs = this.context; + const columnTitles = [ + { title: _("Container"), transforms: [cellWidth(20)], sortable: true }, + { title: _("CPU"), sortable: true }, + { title: _("Memory"), sortable: true }, + { title: _("State"), sortable: true }, + '' + ]; + let filtered = []; + const unusedContainers = []; + + let emptyCaption = _("No containers"); + if (this.props.containers === null) + emptyCaption = _("Loading..."); + else if (this.props.textFilter.length > 0) + emptyCaption = _("No containers that match the current filter"); + else if (this.props.filter === "running") + emptyCaption = _("No running containers"); + + if (this.props.containers !== null) { + filtered = Object.keys(this.props.containers).filter(id => !(this.props.filter === "running") || ["running", "restarting"].includes(this.props.containers[id].State?.Status)); + + const getHealth = id => { + const state = this.props.containers[id]?.State; + return state?.Health?.Status || state?.Healthcheck?.Status; + }; + + filtered.sort((a, b) => { + // Show unhealthy containers first + const a_health = getHealth(a); + const b_health = getHealth(b); + if (a_health !== b_health) { + if (a_health === "unhealthy") + return -1; + if (b_health === "unhealthy") + return 1; + } + return this.props.containers[a].Name > this.props.containers[b].Name ? 1 : -1; + }); + + const prune_states = ["created", "configured", "stopped", "exited"]; + for (const containerid of Object.keys(this.props.containers)) { + const container = this.props.containers[containerid]; + // Ignore pods and running containers + if (!prune_states.includes(container.State)) + continue; + + unusedContainers.push({ + id: container.Id, + name: container.Name, + created: container.Created, + }); + } + } + + // Convert to the search result output + let localImages = null; + let nonIntermediateImages = null; + if (this.props.images) { + localImages = Object.keys(this.props.images).map(id => { + const img = this.props.images[id]; + img.Index = img.RepoTags?.[0] ? img.RepoTags[0].split('/')[0] : ""; + img.Name = utils.image_name(img); + img.toString = function imgToString() { return this.Name }; + return img; + }, []); + nonIntermediateImages = localImages.filter(img => img.Index !== ""); + } + + const createContainer = (inPod) => { + if (nonIntermediateImages) + Dialogs.show( + + {(dockerInfo) => ( + + {(Dialogs) => ( + + )} + + )} + ); + }; + + const filterRunning = ( + + + + {_("Show")} + + + this.props.handleFilterChange(value)}> + + + + + + + + + + + + + + ); + + const sortRows = (rows, direction, idx) => { + // CPU / Memory /States + const isNumeric = idx == 1 || idx == 2 || idx == 3; + const stateOrderMapping = {}; + utils.states.forEach((elem, index) => { + stateOrderMapping[elem] = index; + }); + const sortedRows = rows.sort((a, b) => { + let aitem = a.columns[idx].sortKey ?? a.columns[idx].title; + let bitem = b.columns[idx].sortKey ?? b.columns[idx].title; + // Sort the states based on the order defined in utils. so Running first. + if (idx === 3) { + aitem = stateOrderMapping[aitem]; + bitem = stateOrderMapping[bitem]; + } + if (isNumeric) { + return bitem - aitem; + } else { + return aitem.localeCompare(bitem); + } + }); + return direction === SortByDirection.asc ? sortedRows : sortedRows.reverse(); + }; + + const card = ( + + + {_("Containers")} + + + + {(this.props.containers === null) + ? + : + {/* {caption && */} + {/* */} + {/* */} + {/*

{caption}

*/} + {/* {_("pod group")} */} + {/*
*/} + {/*
*/} + {/*
} */} + { + return this.renderRow(this.props.containersStats, this.props.containers[container], + localImages); + })} + aria-label={_("Containers")} /> +
+ } +
+ {this.state.showPruneUnusedContainersModal && + this.setState({ showPruneUnusedContainersModal: false })} + unusedContainers={unusedContainers} + onAddNotification={this.props.onAddNotification} + serviceAvailable={this.props.serviceAvailable} + user={this.props.user} /> } +
+
+ ); + + return
{card}
; + } +} + +export default Containers; diff --git a/ui/cockpit-docker/src/Containers.scss b/ui/cockpit-docker/src/Containers.scss new file mode 100644 index 0000000..309c7a2 --- /dev/null +++ b/ui/cockpit-docker/src/Containers.scss @@ -0,0 +1,93 @@ +@import "global-variables"; + +.container-pod { + .pf-v5-c-card__header { + border-color: #ddd; + padding-block-start: var(--pf-v5-global--spacer--md); + } + + .pod-header-details { + border-color: #ddd; + margin-block-start: var(--pf-v5-global--spacer--md); + margin-inline: var(--pf-v5-global--spacer--md); + } + + .pod-details-button { + padding-inline: 0; + margin-inline-end: var(--pf-v5-global--spacer--md); + } + + .pod-details-button-color { + color: var(--pf-v5-c-button--m-secondary--Color); + } + + .pf-v5-c-card__title { + padding: 0; + font-weight: var(--pf-v5-global--FontWeight--normal); + font-size: var(--pf-v5-global--FontSize--sm); + + .pod-name { + font-weight: var(--pf-v5-global--FontWeight--bold); + font-size: var(--pf-v5-global--FontSize--md); + padding-inline-end: 1rem; + } + } + + > .pf-v5-c-card__header { + &:not(:last-child) { + padding-block-end: var(--pf-v5-global--spacer-sm); + } + + // Reduce vertical padding of pod header items + > .pf-v5-c-card__title > .pf-l-flex { + row-gap: var(--pf-v5-global--spacer--sm); + } + } +} + +// override ct-card font size, so cpu/ram don't look absurdly big +#app .pf-v5-c-card.container-pod div.pf-v5-c-card__title-text { + font-weight: normal; + font-size: var(--pf-v5-global--FontSize--md); +} + +.pod-stat { + @media (max-width: $pf-v5-global--breakpoint--sm - 1) { + // Place each pod stat on its own row + flex-basis: 100%; + display: grid; + // Give labels to the same space + grid-template-columns: minmax(auto, 4rem) 1fr; + + > svg { + // Hide icons in mobile to be consistent with container lists + display: none; + } + } + + // Center the icons for proper vertical alignment + > svg { + align-self: center; + } +} + +.ct-table-empty td { + padding-block: var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--lg); + padding-inline: var(--pf-v5-global--spacer--md); +} + +/* HACK - force DescriptionList to wrap but not fill the width */ +#container-details-healthcheck { + display: flex; + flex-wrap: wrap; +} + +/* Upstream issue https://github.com/patternfly/patternfly/pull/3714 */ +.containers-containers .pf-v5-c-toolbar__content-section { + gap: var(--pf-v5-global--spacer--sm); +} + +/* Drop the excessive margin for a Dropdown button */ +.containers-containers .pf-v5-c-toolbar__content-section > :nth-last-child(2) { + margin-inline-end: 0; +} diff --git a/ui/cockpit-docker/src/Env.jsx b/ui/cockpit-docker/src/Env.jsx new file mode 100644 index 0000000..e36b658 --- /dev/null +++ b/ui/cockpit-docker/src/Env.jsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { FormHelper } from "cockpit-components-form-helper.jsx"; +import { Grid } from "@patternfly/react-core/dist/esm/layouts/Grid"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import { TrashIcon } from '@patternfly/react-icons'; +import cockpit from 'cockpit'; + +import * as utils from './util.js'; + +const _ = cockpit.gettext; + +export function validateEnvVar(env, key) { + switch (key) { + case "envKey": + if (!env) + return _("Key must not be empty"); + break; + case "envValue": + break; + default: + console.error(`Unknown key "${key}"`); // not-covered: unreachable assertion + } +} + +const handleEnvValue = (key, value, idx, onChange, additem, itemCount, companionField) => { + // Allow the input of KEY=VALUE separated value pairs for bulk import only if the other + // field is not empty. + if (value.includes('=') && !companionField) { + const parts = value.trim().split(" "); + let index = idx; + for (const part of parts) { + const [envKey, ...envVar] = part.split('='); + if (!envKey || !envVar) { + continue; + } + + if (index !== idx) { + additem(); + } + onChange(index, 'envKey', envKey); + onChange(index, 'envValue', envVar.join('=')); + index++; + } + } else { + onChange(idx, key, value); + } +}; + +export const EnvVar = ({ id, item, onChange, idx, removeitem, additem, itemCount, validationFailed, onValidationChange }) => + ( + + + { + utils.validationClear(validationFailed, "envKey", onValidationChange); + utils.validationDebounce(() => onValidationChange({ ...validationFailed, envKey: validateEnvVar(value, "envKey") })); + handleEnvValue('envKey', value, idx, onChange, additem, itemCount, item.envValue); + }} /> + + + + { + utils.validationClear(validationFailed, "envValue", onValidationChange); + utils.validationDebounce(() => onValidationChange({ ...validationFailed, envValue: validateEnvVar(value, "envValue") })); + handleEnvValue('envValue', value, idx, onChange, additem, itemCount, item.envValue); + }} /> + + + + + + } + > + {reason} + + ); +}; + +export default ForceRemoveModal; diff --git a/ui/cockpit-docker/src/ImageDeleteModal.jsx b/ui/cockpit-docker/src/ImageDeleteModal.jsx new file mode 100644 index 0000000..2e97c80 --- /dev/null +++ b/ui/cockpit-docker/src/ImageDeleteModal.jsx @@ -0,0 +1,121 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { List, ListItem } from '@patternfly/react-core/dist/esm/components/List'; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { Stack, StackItem } from "@patternfly/react-core/dist/esm/layouts/Stack"; +import { useDialogs } from "dialogs.jsx"; + +import cockpit from 'cockpit'; + +import ForceRemoveModal from './ForceRemoveModal.jsx'; +import * as client from './client.js'; + +const _ = cockpit.gettext; + +function sortTags(a, b) { + if (a.endsWith(":latest")) + return -1; + if (b.endsWith(":latest")) + return 1; + return a.localeCompare(b); +} + +export const ImageDeleteModal = ({ imageWillDelete, onAddNotification }) => { + const Dialogs = useDialogs(); + const repoTags = imageWillDelete.RepoTags ? imageWillDelete.RepoTags : []; + const isIntermediateImage = repoTags.length === 0; + + const [tags, setTags] = useState(repoTags.sort(sortTags).reduce((acc, item, i) => { + acc[item] = (i === 0); + return acc; + }, {})); + + const checkedTags = Object.keys(tags).sort(sortTags) + .filter(x => tags[x]); + + const onValueChanged = (item, value) => { + setTags(prevState => ({ + ...prevState, + [item]: value, + })); + }; + + const handleRemoveImage = (tags, all) => { + const handleForceRemoveImage = () => { + Dialogs.close(); + return client.delImage(imageWillDelete.Id, true) + .catch(ex => { + const error = cockpit.format(_("Failed to force remove image $0"), imageWillDelete.RepoTags[0]); + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + throw ex; + }); + }; + + Dialogs.close(); + if (all) + client.delImage(imageWillDelete.Id, false) + .catch(ex => { + Dialogs.show(); + }); + else { + // Call another untag once previous one resolved. Calling all at once can result in undefined behavior + const tag = tags.shift(); + const i = tag.lastIndexOf(":"); + client.untagImage(imageWillDelete.Id, tag.substring(0, i), tag.substring(i + 1, tag.length)) + .then(() => { + if (tags.length > 0) + handleRemoveImage(tags, all); + }) + .catch(ex => { + const error = cockpit.format(_("Failed to remove image $0"), tag); + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + } + }; + + const imageName = repoTags[0]?.split(":")[0].split("/").at(-1) ?? _("intermediate"); + + let isAllSelected = null; + if (checkedTags.length === repoTags.length) + isAllSelected = true; + else if (checkedTags.length === 0) + isAllSelected = false; + + return ( + + + + } + > + + { repoTags.length > 1 && {_("Multiple tags exist for this image. Select the tagged images to delete.")} } + + {repoTags.length > 1 && repoTags.forEach(item => onValueChanged(item, checked))} + body={ + repoTags.map(x => ( + -1} + id={"delete-" + x} + aria-label={x} + key={x} + label={x} + onChange={(_event, checked) => onValueChanged(x, checked)} /> + )) + } />} + {repoTags.length === 1 && {repoTags[0]}} + + + + ); +}; diff --git a/ui/cockpit-docker/src/ImageDetails.jsx b/ui/cockpit-docker/src/ImageDetails.jsx new file mode 100644 index 0000000..6266243 --- /dev/null +++ b/ui/cockpit-docker/src/ImageDetails.jsx @@ -0,0 +1,47 @@ +import React from 'react'; +import cockpit from 'cockpit'; +import * as utils from './util.js'; + +import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList"; + +import ImageUsedBy from './ImageUsedBy.jsx'; +const _ = cockpit.gettext; + +const ImageDetails = ({ containers, image, showAll }) => { + return ( + + {image.Command !== "" && + + {_("Command")} + {utils.quote_cmdline(image.Command)} + + } + {image.Entrypoint && + + {_("Entrypoint")} + {image.Entrypoint.join(" ")} + + } + {image.RepoTags && + + {_("Tags")} + {image.RepoTags ? image.RepoTags.join(" ") : ""} + + } + {containers && + + {_("Used by")} + + + } + {image.Ports.length !== 0 && + + {_("Ports")} + {image.Ports.join(', ')} + + } + + ); +}; + +export default ImageDetails; diff --git a/ui/cockpit-docker/src/ImageHistory.jsx b/ui/cockpit-docker/src/ImageHistory.jsx new file mode 100644 index 0000000..585dff8 --- /dev/null +++ b/ui/cockpit-docker/src/ImageHistory.jsx @@ -0,0 +1,64 @@ +import React, { useState, useEffect } from 'react'; +import cockpit from 'cockpit'; +import * as utils from './util.js'; +import * as client from './client.js'; + +import { ListingTable } from "cockpit-components-table.jsx"; + +const _ = cockpit.gettext; + +const IdColumn = Id => { + Id = utils.truncate_id(Id); + // Not an id but or something else + if (/<[a-z]+>/.test(Id)) { + return
{Id}
; + } + return Id; +}; + +const ImageDetails = ({ image }) => { + const [history, setHistory] = useState([]); + const [error, setError] = useState(null); + const id = image.Id; + + useEffect(() => { + client.imageHistory(id).then(setHistory) + .catch(ex => { + console.error("Cannot get image history", ex); + setError(true); + }); + }, [id]); + + const columns = ["ID", _("Created"), _("Created by"), _("Size"), _("Comments")]; + let showComments = false; + const rows = history.map(layer => { + const row = { + columns: [ + { title: IdColumn(layer.Id), props: { className: "ignore-pixels" } }, + { title: utils.localize_time(layer.Created), props: { className: "ignore-pixels" } }, + { title: layer.CreatedBy, props: { className: "ignore-pixels" } }, + { title: cockpit.format_bytes(layer.Size), props: { className: "ignore-pixels" } }, + { title: layer.Comment, props: { className: "ignore-pixels" } }, + ] + }; + if (layer.Comment) { + showComments = true; + } + return row; + }); + + if (!showComments) { + columns.pop(); + } + + return ( + + ); +}; + +export default ImageDetails; diff --git a/ui/cockpit-docker/src/ImageRunModal.jsx b/ui/cockpit-docker/src/ImageRunModal.jsx new file mode 100644 index 0000000..9baff84 --- /dev/null +++ b/ui/cockpit-docker/src/ImageRunModal.jsx @@ -0,0 +1,1114 @@ +import React from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { FormHelper } from "cockpit-components-form-helper.jsx"; +import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect"; +import { Grid, GridItem } from "@patternfly/react-core/dist/esm/layouts/Grid"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { Radio } from "@patternfly/react-core/dist/esm/components/Radio"; +import { Select, SelectGroup, SelectOption, SelectVariant } from "@patternfly/react-core/dist/esm/deprecated/components/Select"; +import { NumberInput } from "@patternfly/react-core/dist/esm/components/NumberInput"; +import { InputGroup, InputGroupText } from "@patternfly/react-core/dist/esm/components/InputGroup"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import { Tab, TabTitleText, Tabs } from "@patternfly/react-core/dist/esm/components/Tabs"; +import { Text, TextContent, TextList, TextListItem, TextVariants } from "@patternfly/react-core/dist/esm/components/Text"; +import { ToggleGroup, ToggleGroupItem } from "@patternfly/react-core/dist/esm/components/ToggleGroup"; +import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { Popover } from "@patternfly/react-core/dist/esm/components/Popover"; +import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; +import * as dockerNames from 'docker-names'; + +import { ErrorNotification } from './Notification.jsx'; +import * as utils from './util.js'; +import * as client from './client.js'; +import rest from './rest.js'; +import cockpit from 'cockpit'; +import { onDownloadContainer, onDownloadContainerFinished } from './Containers.jsx'; +import { PublishPort, validatePublishPort } from './PublishPort.jsx'; +import { DynamicListForm } from 'cockpit-components-dynamic-list.jsx'; +import { validateVolume, Volume } from './Volume.jsx'; +import { EnvVar, validateEnvVar } from './Env.jsx'; + +import { debounce } from 'throttle-debounce'; + +import "./ImageRunModal.scss"; + +const _ = cockpit.gettext; + +const units = { + KB: { + name: "KB", + baseExponent: 1, + }, + MB: { + name: "MB", + baseExponent: 2, + }, + GB: { + name: "GB", + baseExponent: 3, + }, +}; + +// healthchecks.go HealthCheckOnFailureAction +const HealthCheckOnFailureActionOrder = [ + { value: 0, label: _("No action") }, + { value: 3, label: _("Restart") }, + { value: 4, label: _("Stop") }, + { value: 2, label: _("Force stop") }, +]; + +export class ImageRunModal extends React.Component { + constructor(props) { + super(props); + + let command = ""; + if (this.props.image && this.props.image.Command) { + command = utils.quote_cmdline(this.props.image.Command); + } + + const entrypoint = utils.quote_cmdline(this.props.image?.Entrypoint); + + let selectedImage = ""; + if (this.props.image) { + selectedImage = utils.image_name(this.props.image); + } + + this.state = { + command, + containerName: dockerNames.getRandomName(), + entrypoint, + env: [], + hasTTY: true, + publish: [], + image: props.image, + memory: 512, + cpuShares: 1024, + memoryConfigure: false, + cpuSharesConfigure: false, + memoryUnit: 'MB', + validationFailed: {}, + volumes: [], + restartPolicy: "no", + restartTries: 5, + pullLatestImage: false, + activeTabKey: 0, + /* image select */ + selectedImage, + searchFinished: false, + searchInProgress: false, + searchText: "", + imageResults: {}, + isImageSelectOpen: false, + searchByRegistry: 'all', + /* health check */ + healthcheck_command: "", + healthcheck_shell: false, + healthcheck_interval: 30, + healthcheck_timeout: 30, + healthcheck_start_period: 0, + healthcheck_retries: 3, + healthcheck_action: 0, + }; + this.getCreateConfig = this.getCreateConfig.bind(this); + this.onValueChanged = this.onValueChanged.bind(this); + } + + componentDidMount() { + this._isMounted = true; + this.onSearchTriggered(this.state.searchText); + } + + componentWillUnmount() { + this._isMounted = false; + + if (this.activeConnection) + this.activeConnection.close(); + } + + getCreateConfig() { + const createConfig = {}; + createConfig.HostConfig = {}; + + if (this.state.image) { + createConfig.image = this.state.image.RepoTags.length > 0 ? this.state.image.RepoTags[0] : ""; + } else { + let img = this.state.selectedImage.Name; + // Make implicit :latest + if (!img.includes(":")) { + img += ":latest"; + } + createConfig.image = img; + } + + if (this.state.containerName) + createConfig.name = this.state.containerName; + + if (this.state.command) + createConfig.command = utils.unquote_cmdline(this.state.command); + + if (this.state.memoryConfigure && this.state.memory) { + const memorySize = this.state.memory * (1000 ** units[this.state.memoryUnit].baseExponent); + createConfig.HostConfig.Memory = memorySize; + } + + if (this.state.cpuSharesConfigure && parseInt(this.state.cpuShares) !== 0) + createConfig.HostConfig.CpuShares = parseInt(this.state.cpuShares); + + createConfig.terminal = this.state.hasTTY; + if (this.state.publish.some(port => port !== undefined)) { + const PortBindings = {}; + const ExposedPorts = {}; + this.state.publish.filter(port => port?.containerPort).forEach(item => { + ExposedPorts[item.containerPort + "/" + item.protocol] = {}; + const mapping = { HostPort: item.hostPort }; + if (item.IP) + mapping.HostIp = item.hostIp; + PortBindings[item.containerPort + "/" + item.protocol] = [mapping]; + }); + + createConfig.HostConfig.PortBindings = PortBindings; + createConfig.ExposedPorts = ExposedPorts; + } + if (this.state.env.some(item => item !== undefined)) { + const envs = []; + this.state.env.forEach(item => { + if (item !== undefined) + envs.push(item.envKey + "=" + item.envValue); + }); + createConfig.Env = envs; + } + if (this.state.volumes.some(volume => volume !== undefined)) { + createConfig.HostConfig.mounts = this.state.volumes + .filter(volume => volume?.hostPath && volume?.containerPath) + .map(volume => { + return { + Source: volume.hostPath, + Target: volume.containerPath, + Type: "bind", + ReadOnly: volume.ReadOnly + }; + }); + } + + if (this.state.restartPolicy !== "no") { + createConfig.HostConfig.RestartPolicy = { Name: this.state.restartPolicy }; + if (this.state.restartPolicy === "on-failure" && this.state.restartTries !== null) { + createConfig.HostConfig.RestartPolicy.MaximumRetryCount = parseInt(this.state.restartTries); + } + if (this.state.restartPolicy === "always" && (this.props.serviceAvailable)) { + this.enableDockerRestartService(); + } + } + + if (this.state.healthcheck_command !== "") { + const test = utils.unquote_cmdline(this.state.healthcheck_command); + if (this.state.healthcheck_shell) { + test.unshift("CMD-SHELL"); + } else { + test.unshift("CMD"); + } + createConfig.Healthcheck = { + Interval: parseInt(this.state.healthcheck_interval) * 1000000000, + Retries: this.state.healthcheck_retries, + StartPeriod: parseInt(this.state.healthcheck_start_period) * 1000000000, + Test: test, + Timeout: parseInt(this.state.healthcheck_timeout) * 1000000000, + }; + createConfig.health_check_on_failure_action = parseInt(this.state.healthcheck_action); + } + + console.log("createConfig", createConfig); + + return createConfig; + } + + createContainer = (createConfig, runImage) => { + const Dialogs = this.props.dialogs; + client.createContainer(createConfig) + .then(reply => { + if (runImage) { + client.postContainer("start", reply.Id, {}) + .then(() => Dialogs.close()) + .catch(ex => { + // If container failed to start remove it, so a user can fix the settings and retry and + // won't get another error that the container name is already taken. + client.delContainer(reply.Id, true) + .then(() => { + this.setState({ + dialogError: _("Container failed to be started"), + dialogErrorDetail: cockpit.format("$0: $1", ex.reason, ex.message) + }); + }) + .catch(ex => { + this.setState({ + dialogError: _("Failed to clean up container"), + dialogErrorDetail: cockpit.format("$0: $1", ex.reason, ex.message) + }); + }); + }); + } else { + Dialogs.close(); + } + }) + .catch(ex => { + this.setState({ + dialogError: _("Container failed to be created"), + dialogErrorDetail: cockpit.format("$0: $1", ex.reason, ex.message) + }); + }); + }; + + async onCreateClicked(runImage = false) { + if (!await this.validateForm()) + return; + + const Dialogs = this.props.dialogs; + const createConfig = this.getCreateConfig(); + const { pullLatestImage } = this.state; + let imageExists = true; + + try { + await client.imageExists(createConfig.image); + } catch (error) { + imageExists = false; + } + + if (imageExists && !pullLatestImage) { + this.createContainer(createConfig, runImage); + } else { + Dialogs.close(); + const tempImage = { ...createConfig }; + + // Assign temporary properties to allow rendering + tempImage.Id = tempImage.name; + tempImage.State = { Status: _("downloading") }; + tempImage.Created = new Date(); + tempImage.Name = [tempImage.name]; + tempImage.Image = createConfig.image; + tempImage.isDownloading = true; + + onDownloadContainer(tempImage); + + client.pullImage(createConfig.image).then(reply => { + client.createContainer(createConfig) + .then(reply => { + if (runImage) { + client.postContainer("start", reply.Id, {}) + .then(() => onDownloadContainerFinished(createConfig)) + .catch(ex => { + onDownloadContainerFinished(createConfig); + const error = cockpit.format(_("Failed to run container $0"), tempImage.name); + this.props.onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + } + }) + .catch(ex => { + onDownloadContainerFinished(createConfig); + const error = cockpit.format(_("Failed to create container $0"), tempImage.name); + this.props.onAddNotification({ type: 'danger', error, errorDetail: ex.reason }); + }); + }) + .catch(ex => { + onDownloadContainerFinished(createConfig); + const error = cockpit.format(_("Failed to pull image $0"), tempImage.image); + this.props.onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + }); + } + } + + onValueChanged(key, value) { + this.setState({ [key]: value }); + } + + onPlusOne(key) { + this.setState(state => ({ [key]: parseInt(state[key]) + 1 })); + } + + onMinusOne(key) { + this.setState(state => ({ [key]: parseInt(state[key]) - 1 })); + } + + handleTabClick = (event, tabIndex) => { + // Prevent the form from being submitted. + event.preventDefault(); + this.setState({ + activeTabKey: tabIndex, + }); + }; + + onSearchTriggered = value => { + // Do not call the SearchImage API if the input string is not at least 2 chars, + // The comparison was done considering the fact that we miss always one letter due to delayed setState + if (value.length < 2) + return; + + // Don't search for a value with a tag specified + const patt = /:[\w|\d]+$/; + if (patt.test(value)) { + return; + } + + if (this.activeConnection) + this.activeConnection.close(); + + this.setState({ searchFinished: false, searchInProgress: true }); + this.activeConnection = rest.connect(client.getAddress()); + let searches = []; + + // If there are registries configured search in them, or if a user searches for `docker.io/cockpit` let + // docker search in the user specified registry. + if (Object.keys(this.props.dockerInfo.registries).length !== 0 || value.includes('/')) { + searches.push(this.activeConnection.call({ + method: "GET", + path: client.VERSION + "/images/search", + body: "", + params: { + term: value, + } + })); + } else { + searches = searches.concat(utils.fallbackRegistries.map(registry => + this.activeConnection.call({ + method: "GET", + path: client.VERSION + "/images/search", + body: "", + params: { + term: registry + "/" + value + } + }))); + } + + Promise.allSettled(searches) + .then(reply => { + if (reply && this._isMounted) { + let imageResults = []; + let dialogError = ""; + let dialogErrorDetail = ""; + + for (const result of reply) { + if (result.status === "fulfilled") { + imageResults = imageResults.concat(JSON.parse(result.value)); + } else { + dialogError = _("Failed to search for new images"); + // TODO: add registry context, docker does not include it in the reply. + dialogErrorDetail = result.reason ? cockpit.format(_("Failed to search for images: $0"), result.reason.message) : _("Failed to search for images."); + } + } + // Group images on registry + const images = {}; + imageResults.forEach(image => { + // Add Tag is it's there + image.toString = function imageToString() { + if (this.Tag) { + return this.Name + ':' + this.Tag; + } + return this.Name; + }; + + let index = image.Index; + + // listTags results do not return the registry Index. + // https://github.com/containers/common/pull/803 + if (!index) { + index = image.Name.split('/')[0]; + } + + if (index in images) { + images[index].push(image); + } else { + images[index] = [image]; + } + }); + this.setState({ + imageResults: images || {}, + searchFinished: true, + searchInProgress: false, + dialogError, + dialogErrorDetail, + }); + } + }); + }; + + clearImageSelection = () => { + // Reset command if it was prefilled + let command = this.state.command; + if (this.state.command === utils.quote_cmdline(this.state.selectedImage?.Command)) + command = ""; + + this.setState({ + selectedImage: "", + image: "", + isImageSelectOpen: false, + imageResults: {}, + searchText: "", + searchFinished: false, + command, + entrypoint: "", + }); + }; + + onImageSelectToggle = (_, isOpen) => { + this.setState({ + isImageSelectOpen: isOpen, + }); + }; + + onImageSelect = (event, value, placeholder) => { + if (event === undefined) + return; + + let command = this.state.command; + if (value.Command && !command) + command = utils.quote_cmdline(value.Command); + + const entrypoint = utils.quote_cmdline(value?.Entrypoint); + + this.setState({ + selectedImage: value, + isImageSelectOpen: false, + command, + entrypoint, + }); + }; + + handleImageSelectInput = value => { + this.setState({ + searchText: value, + // Reset searchFinished status when text input changes + searchFinished: false, + selectedImage: "", + }); + this.onSearchTriggered(value); + }; + + debouncedInputChanged = debounce(300, this.handleImageSelectInput); + + handleOwnerSelect = (event) => { + const value = event.currentTarget.value; + this.setState({ + owner: value + }); + }; + + filterImages = () => { + const { localImages } = this.props; + const { imageResults, searchText } = this.state; + const local = _("Local images"); + const images = { ...imageResults }; + + let imageRegistries = []; + if (this.state.searchByRegistry == 'local' || this.state.searchByRegistry == 'all') { + imageRegistries.push(local); + images[local] = localImages; + + if (this.state.searchByRegistry == 'all') + imageRegistries = imageRegistries.concat(Object.keys(imageResults)); + } else { + imageRegistries.push(this.state.searchByRegistry); + } + + // Strip out all non-allowed container image characters when filtering. + let regexString = searchText.replace(/[^\w_.:-]/g, ""); + // Strip image registry option if set for comparing results for docker.io searching for docker.io/fedora + // returns docker.io/$username/fedora for example. + if (regexString.includes('/')) { + regexString = searchText.replace(searchText.split('/')[0], ''); + } + const input = new RegExp(regexString, 'i'); + + const results = imageRegistries + .map((reg, index) => { + const filtered = (reg in images ? images[reg] : []) + .filter(image => { + return image.Name.search(input) !== -1; + }) + .map((image, index) => { + return ( + + ); + }); + + if (filtered.length === 0) { + return []; + } else { + return ( + + {filtered} + + ); + } + }) + .filter(group => group.length !== 0); // filter out empty groups + + // Remove when there is a filter selected. + if (this.state.searchByRegistry !== 'all' && imageRegistries.length === 1 && results.length === 1) { + return results[0].props.children; + } + + return results; + }; + + // Similar to the output of docker search and docker's //images/search endpoint only show the root domain. + truncateRegistryDomain = (domain) => { + const parts = domain.split('.'); + if (parts.length > 2) { + return parts[parts.length - 2] + "." + parts[parts.length - 1]; + } + return domain; + }; + + enableDockerRestartService = () => { + const argv = ["systemctl", "enable", "docker.service"]; + + cockpit.spawn(argv, { superuser: "require", err: "message" }) + .catch(err => { + console.warn("Failed to enable docker.service:", JSON.stringify(err)); + }); + }; + + isFormInvalid = validationFailed => { + const groupHasError = row => row && Object.values(row) + .filter(val => val) // Filter out empty/undefined properties + .length > 0; // If one field has error, the whole group (dynamicList) is invalid + + // If at least one group is invalid, then the whole form is invalid + return validationFailed.publish?.some(groupHasError) || + validationFailed.volumes?.some(groupHasError) || + validationFailed.env?.some(groupHasError) || + !!validationFailed.containerName; + }; + + async validateContainerName(containerName) { + try { + await client.containerExists(containerName); + } catch (error) { + return; + } + return _("Name already in use"); + } + + async validateForm() { + const { publish, volumes, env, containerName } = this.state; + const validationFailed = { }; + + const publishValidation = publish.map(a => { + if (a === undefined) + return undefined; + + return { + IP: validatePublishPort(a.IP, "IP"), + hostPort: validatePublishPort(a.hostPort, "hostPort"), + containerPort: validatePublishPort(a.containerPort, "containerPort"), + }; + }); + if (publishValidation.some(entry => entry && Object.keys(entry).length > 0)) + validationFailed.publish = publishValidation; + + const volumesValidation = volumes.map(a => { + if (a === undefined) + return undefined; + + return { + hostPath: validateVolume(a.hostPath, "hostPath"), + containerPath: validateVolume(a.containerPath, "containerPath"), + }; + }); + if (volumesValidation.some(entry => entry && Object.keys(entry).length > 0)) + validationFailed.volumes = volumesValidation; + + const envValidation = env.map(a => { + if (a === undefined) + return undefined; + + return { + envKey: validateEnvVar(a.envKey, "envKey"), + envValue: validateEnvVar(a.envValue, "envValue"), + }; + }); + if (envValidation.some(entry => entry && Object.keys(entry).length > 0)) + validationFailed.env = envValidation; + + const containerNameValidation = await this.validateContainerName(containerName); + + if (containerNameValidation) + validationFailed.containerName = containerNameValidation; + + this.setState({ validationFailed }); + + return !this.isFormInvalid(validationFailed); + } + + /* Updates a validation object of the whole dynamic list's form (e.g. the whole port-mapping form) + * + * Arguments + * - key: [publish/volumes/env] - Specifies the validation of which dynamic form of the Image run dialog is being updated + * - value: An array of validation errors of the form. Each item of the array represents a row of the dynamic list. + * Index needs to corellate with a row number + */ + dynamicListOnValidationChange = (key, value) => { + const validationFailedDelta = { ...this.state.validationFailed }; + + validationFailedDelta[key] = value; + + if (validationFailedDelta[key].every(a => a === undefined)) + delete validationFailedDelta[key]; + + this.onValueChanged('validationFailed', validationFailedDelta); + }; + + render() { + const Dialogs = this.props.dialogs; + const { registries, dockerRestartAvailable, selinuxAvailable, version } = this.props.dockerInfo; + const { image } = this.props; + const dialogValues = this.state; + const { activeTabKey, selectedImage } = this.state; + + let imageListOptions = []; + if (!image) { + imageListOptions = this.filterImages(); + } + + const localImage = this.state.image || (selectedImage && this.props.localImages.some(img => img.Id === selectedImage.Id)); + const dockerRegistries = registries && registries.search ? registries.search : utils.fallbackRegistries; + + // Add the search component + const footer = ( + + { + ev.stopPropagation(); + this.setState({ searchByRegistry: 'all' }); + }} + // Ignore SelectToggle's touchstart's default behaviour + onTouchStart={ev => { + ev.stopPropagation(); + }} + /> + { + ev.stopPropagation(); + this.setState({ searchByRegistry: 'local' }); + }} + onTouchStart={ev => { + ev.stopPropagation(); + }} + /> + {dockerRegistries.map(registry => { + const index = this.truncateRegistryDomain(registry); + return ( + { + ev.stopPropagation(); + this.setState({ searchByRegistry: index }); + } } + onTouchStart={ ev => ev.stopPropagation() } + /> + ); + })} + + ); + + const defaultBody = ( +
+ {this.state.dialogError && } + + { + utils.validationClear(dialogValues.validationFailed, "containerName", (value) => this.onValueChanged("validationFailed", value)); + utils.validationDebounce(async () => { + const delta = await this.validateContainerName(value); + if (delta) + this.onValueChanged("validationFailed", { ...dialogValues.validationFailed, containerName: delta }); + }); + this.onValueChanged('containerName', value); + }} /> + + + + {_("Details")}} className="pf-v5-c-form pf-m-horizontal"> + + {_("host[:port]/[user]/container[:tag]")} + {cockpit.format(_("Example: $0"), "quay.io//busybox")} + {cockpit.format(_("Searching: $0"), "quay.io/busybox")} + + }> + + + } + > + + + + {(image || localImage) && + + this.onValueChanged('pullLatestImage', value)} label={_("Pull latest image")} + /> + + } + + {dialogValues.entrypoint && + + {dialogValues.entrypoint} + + } + + + this.onValueChanged('command', value)} /> + + + + this.onValueChanged('hasTTY', checked)} /> + + + + + this.onValueChanged('memoryConfigure', checked)} /> + !this.state.memoryConfigure && this.onValueChanged('memoryConfigure', true)} + onPlus={() => this.onPlusOne('memory')} + onMinus={() => this.onMinusOne('memory')} + minusBtnAriaLabel={_("Decrease memory")} + plusBtnAriaLabel={_("Increase memory")} + onChange={ev => this.onValueChanged('memory', parseInt(ev.target.value) < 0 ? 0 : ev.target.value)} /> + this.onValueChanged('memoryUnit', value)}> + + + + + + + + + + + }> + + this.onValueChanged('cpuSharesConfigure', checked)} /> + !this.state.cpuSharesConfigure && this.onValueChanged('cpuSharesConfigure', true)} + min={2} + max={262144} + isDisabled={!this.state.cpuSharesConfigure} + onPlus={() => this.onPlusOne('cpuShares')} + onMinus={() => this.onMinusOne('cpuShares')} + minusBtnAriaLabel={_("Decrease CPU shares")} + plusBtnAriaLabel={_("Increase CPU shares")} + onChange={ev => this.onValueChanged('cpuShares', parseInt(ev.target.value) < 2 ? 2 : ev.target.value)} /> + + + {(dockerRestartAvailable) && + + + + + + } + > + this.onValueChanged('restartPolicy', value)}> + + + + + + + {dialogValues.restartPolicy === "on-failure" && + + this.onMinusOne('restartTries')} + onPlus={() => this.onPlusOne('restartTries')} + onChange={ev => this.onValueChanged('restartTries', parseInt(ev.target.value) < 1 ? 1 : ev.target.value)} + /> + + } + + } + + {_("Integration")}} id="create-image-dialog-tab-integration" className="pf-v5-c-form"> + + this.dynamicListOnValidationChange('publish', value)} + onChange={value => this.onValueChanged('publish', value)} + default={{ IP: null, containerPort: null, hostPort: null, protocol: 'tcp' }} + itemcomponent={ } /> + this.dynamicListOnValidationChange('volumes', value)} + onChange={value => this.onValueChanged('volumes', value)} + default={{ containerPath: null, hostPath: null, readOnly: false }} + options={{ selinuxAvailable }} + itemcomponent={ } /> + + this.dynamicListOnValidationChange('env', value)} + onChange={value => this.onValueChanged('env', value)} + default={{ envKey: null, envValue: null }} + helperText={_("Paste one or more lines of key=value pairs into any field for bulk import")} + itemcomponent={ } /> + + {_("Health check")}} id="create-image-dialog-tab-healthcheck" className="pf-v5-c-form pf-m-horizontal"> + + this.onValueChanged('healthcheck_command', value)} /> + + + + this.onValueChanged('healthcheck_shell', checked)} /> + + + + + + }> + + this.onMinusOne('healthcheck_interval')} + onPlus={() => this.onPlusOne('healthcheck_interval')} + onChange={ev => this.onValueChanged('healthcheck_interval', parseInt(ev.target.value) < 0 ? 0 : ev.target.value)} /> + {_("seconds")} + + + + + + }> + + this.onMinusOne('healthcheck_timeout')} + onPlus={() => this.onPlusOne('healthcheck_timeout')} + onChange={ev => this.onValueChanged('healthcheck_timeout', parseInt(ev.target.value) < 0 ? 0 : ev.target.value)} /> + {_("seconds")} + + + + + + }> + + this.onMinusOne('healthcheck_start_period')} + onPlus={() => this.onPlusOne('healthcheck_start_period')} + onChange={ev => this.onValueChanged('healthcheck_start_period', parseInt(ev.target.value) < 0 ? 0 : ev.target.value)} /> + {_("seconds")} + + + + + + }> + this.onMinusOne('healthcheck_retries')} + onPlus={() => this.onPlusOne('healthcheck_retries')} + onChange={ev => this.onValueChanged('healthcheck_retries', parseInt(ev.target.value) < 0 ? 0 : ev.target.value)} /> + + {version.localeCompare("4.3", undefined, { numeric: true, sensitivity: 'base' }) >= 0 && + + + + }> + {HealthCheckOnFailureActionOrder.map(item => + this.onValueChanged('healthcheck_action', item.value)} /> + )} + + } + + + + ); + return ( + { + if (this.state.isImageSelectOpen) { + this.onImageSelectToggle(!this.state.isImageSelectOpen); + } else { + Dialogs.close(); + } + }} + title={_("Create container")} + footer={<> + + + + } + > + {defaultBody} + + ); + } +} diff --git a/ui/cockpit-docker/src/ImageRunModal.scss b/ui/cockpit-docker/src/ImageRunModal.scss new file mode 100644 index 0000000..6a5399d --- /dev/null +++ b/ui/cockpit-docker/src/ImageRunModal.scss @@ -0,0 +1,47 @@ +@import "global-variables"; + +// Ensure the width fits within the screen boundaries (with padding on the sides) +.pf-v5-c-select__menu { + // 3xl is the left+right padding for an iPhone SE; + // this works on other screen sizes as well + max-inline-size: calc(100vw - var(--pf-v5-global--spacer--3xl)); +} + +// Make sure the footer is visible with more then 5 results. +.pf-c-select__menu-list { + // 35% viewport height is for 1280x720; + // since it picks the min of the two, it works everywhere + max-block-size: min(20rem, 35vh); + overflow: hidden scroll; +} + +// Fix the dot next to spinner: https://github.com/patternfly/patternfly-react/issues/6383 +.pf-v5-c-select__list-item.pf-m-loading { + list-style-type: none; +} + +.image-search-footer { + flex-wrap: wrap; + + .pf-v5-c-toggle-group__text { + word-wrap: break-word; + } +} + + // PF4 does not yet support multiple form fields for the same label +.ct-input-group-spacer-sm.pf-v5-l-flex { + // Limit width for select entries and inputs in the input groups otherwise they take up the whole space + > .pf-v5-c-select, .pf-v5-c-form-control:not(.pf-v5-c-select__toggle-typeahead) { + max-inline-size: 8ch; + } +} + +// HACK: A local copy of pf-m-horizontal (as ct-m-horizontal), +// but applied at the FormGroup level instead of Form +@media (min-width: $pf-v5-global--breakpoint--md) { + .pf-v5-c-form__group.ct-m-horizontal { + display: grid; + grid-column-gap: var(--pf-v5-c-form--m-horizontal__group-label--md--GridColumnGap); + grid-template-columns: var(--pf-v5-c-form--m-horizontal__group-label--md--GridColumnWidth) var(--pf-v5-c-form--m-horizontal__group-control--md--GridColumnWidth); + } +} diff --git a/ui/cockpit-docker/src/ImageSearchModal.css b/ui/cockpit-docker/src/ImageSearchModal.css new file mode 100644 index 0000000..ff09dff --- /dev/null +++ b/ui/cockpit-docker/src/ImageSearchModal.css @@ -0,0 +1,59 @@ +.docker-search .pf-v5-c-modal-box__body { + display: grid; + grid-auto-flow: row; + overflow: hidden; + grid-template-rows: auto auto 1fr; + grid-gap: var(--pf-v5-global--spacer--sm); +} + +.image-list-item { + display: grid; + grid-gap: 0 1rem; +} + +.image-list-item + .image-list-item { + border-block-start: 1px solid var(--pf-v5-global--BorderColor--200); +} + +.image-list-item > .image-name { + color: var(--pf-v5-global--Color--100); +} + +@media (min-width: 768px) { + .image-list-item { + grid-template-columns: 1fr max-content; + } +} + +.docker-search .image-search-modal-footer-grid { + display: grid; + grid-template-columns: 1fr auto auto; + grid-gap: 0.25rem; +} + +.image-tag-entry { + max-inline-size: 15rem; +} + +@media (max-width: 340px) { + /* Shrink buttons to accommodate iPhone 5/SE */ + .docker-search .modal-footer > .btn { + padding-inline: 0.25rem; + } +} + +.image-search-tag-form { + margin-block-end: var(--pf-v5-global--spacer--md); +} + +.docker-search .pf-v5-c-modal-box__footer { + display: initial; +} + +.docker-search .pf-v5-c-data-list { + overflow-y: auto; +} + +.docker-search .pf-v5-l-flex .pf-v5-c-form__group:nth-child(2) { + grid-template-columns: 2rem var(--pf-v5-c-form--m-horizontal__group-control--md--GridColumnWidth); +} diff --git a/ui/cockpit-docker/src/ImageSearchModal.jsx b/ui/cockpit-docker/src/ImageSearchModal.jsx new file mode 100644 index 0000000..8ebec49 --- /dev/null +++ b/ui/cockpit-docker/src/ImageSearchModal.jsx @@ -0,0 +1,212 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { DataList, DataListCell, DataListItem, DataListItemCells, DataListItemRow } from "@patternfly/react-core/dist/esm/components/DataList"; +import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { Radio } from "@patternfly/react-core/dist/esm/components/Radio"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import { ExclamationCircleIcon } from '@patternfly/react-icons'; + +import { EmptyStatePanel } from "cockpit-components-empty-state.jsx"; +import { ErrorNotification } from './Notification.jsx'; +import cockpit from 'cockpit'; +import rest from './rest.js'; +import * as client from './client.js'; +import { fallbackRegistries, useDockerInfo } from './util.js'; +import { useDialogs } from "dialogs.jsx"; + +import './ImageSearchModal.css'; + +const _ = cockpit.gettext; + +export const ImageSearchModal = ({ downloadImage }) => { + const [searchInProgress, setSearchInProgress] = useState(false); + const [searchFinished, setSearchFinished] = useState(false); + const [imageIdentifier, setImageIdentifier] = useState(''); + const [imageList, setImageList] = useState([]); + const [imageTag, setImageTag] = useState(""); + const [selectedRegistry, setSelectedRegistry] = useState(""); + const [selected, setSelected] = useState(""); + const [dialogError, setDialogError] = useState(""); + const [dialogErrorDetail, setDialogErrorDetail] = useState(""); + const [typingTimeout, setTypingTimeout] = useState(null); + + let activeConnection = null; + const { registries } = useDockerInfo(); + const Dialogs = useDialogs(); + // Registries to use for searching + const searchRegistries = registries.search && registries.length !== 0 ? registries.search : fallbackRegistries; + + // Don't use on selectedRegistry state variable for finding out the + // registry to search in as with useState we can only call something after a + // state update with useEffect but as onSearchTriggered also changes state we + // can't use that so instead we pass the selected registry. + const onSearchTriggered = (searchRegistry = "", forceSearch = false) => { + // When search re-triggers close any existing active connection + activeConnection = rest.connect(client.getAddress()); + if (activeConnection) + activeConnection.close(); + setSearchFinished(false); + + // Do not call the SearchImage API if the input string is not at least 2 chars, + // unless Enter is pressed, which should force start the search. + // The comparison was done considering the fact that we miss always one letter due to delayed setState + if (imageIdentifier.length < 2 && !forceSearch) + return; + + setSearchInProgress(true); + + let queryRegistries = searchRegistries; + if (searchRegistry !== "") { + queryRegistries = [searchRegistry]; + } + // if a user searches for `docker.io/cockpit` let docker search in the user specified registry. + if (imageIdentifier.includes('/')) { + queryRegistries = [""]; + } + + const searches = queryRegistries.map(rr => { + const registry = rr.length < 1 || rr[rr.length - 1] === "/" ? rr : rr + "/"; + return activeConnection.call({ + method: "GET", + path: client.VERSION + "/images/search", + body: "", + params: { + term: registry + imageIdentifier + } + }); + }); + + Promise.allSettled(searches) + .then(reply => { + if (reply) { + let results = []; + + for (const result of reply) { + if (result.status === "fulfilled") { + results = results.concat(JSON.parse(result.value)); + // console.log(results); + } else { + setDialogError(_("Failed to search for new images")); + setDialogErrorDetail(result.reason ? cockpit.format(_("Failed to search for images: $0"), result.reason.message) : _("Failed to search for images.")); + } + } + + setImageList(results || []); + setSearchInProgress(false); + setSearchFinished(true); + } + }); + }; + + const onKeyDown = (e) => { + if (e.key != ' ') { // Space should not trigger search + const forceSearch = e.key == 'Enter'; + if (forceSearch) { + e.preventDefault(); + } + + // Reset the timer, to make the http call after 250MS + clearTimeout(typingTimeout); + setTypingTimeout(setTimeout(() => onSearchTriggered(selectedRegistry, forceSearch), 250)); + } + }; + + const onDownloadClicked = () => { + const selectedImageName = imageList[selected].name; + if (activeConnection) + activeConnection.close(); + Dialogs.close(); + downloadImage(selectedImageName, imageTag); + }; + + const handleClose = () => { + if (activeConnection) + activeConnection.close(); + Dialogs.close(); + }; + + return ( + +
+ + setImageTag(value)} /> + +
+ + + } + > +
+ {dialogError && } + + + setImageIdentifier(value)} /> + + + { setSelectedRegistry(value); clearTimeout(typingTimeout); onSearchTriggered(value, false) }}> + + {(searchRegistries || []).map(r => )} + + + + + + {searchInProgress && } + + {((!searchInProgress && !searchFinished) || imageIdentifier == "") && } + + {searchFinished && imageIdentifier !== '' && <> + {imageList.length == 0 && } + {imageList.length > 0 && + setSelected(key.split('-').slice(-1)[0])}> + {imageList.map((image, iter) => { + return ( + + + + {image.name} + , + + {image.description} + + ]} + /> + + + ); + })} + } + } +
+ ); +}; diff --git a/ui/cockpit-docker/src/ImageUsedBy.jsx b/ui/cockpit-docker/src/ImageUsedBy.jsx new file mode 100644 index 0000000..6db307b --- /dev/null +++ b/ui/cockpit-docker/src/ImageUsedBy.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import cockpit from 'cockpit'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Badge } from "@patternfly/react-core/dist/esm/components/Badge"; +import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { List, ListItem } from "@patternfly/react-core/dist/esm/components/List"; + +const _ = cockpit.gettext; + +const ImageUsedBy = ({ containers, showAll }) => { + if (containers === null) + return _("Loading..."); + if (containers === undefined) + return _("No containers are using this image"); + + return ( + + {containers.map(c => { + const container = c.container; + const isRunning = container.State?.Status === "running"; + return ( + + + + {isRunning && {_("Running")}} + + + ); + })} + + ); +}; + +export default ImageUsedBy; diff --git a/ui/cockpit-docker/src/Images.css b/ui/cockpit-docker/src/Images.css new file mode 100644 index 0000000..b93b2ac --- /dev/null +++ b/ui/cockpit-docker/src/Images.css @@ -0,0 +1,23 @@ +#containers-images div.download-in-progress { + color: grey; + font-weight: bold; +} + +/* Danger dropdown items should be red */ +.pf-v5-c-dropdown__menu-item.pf-m-danger:not(.pf-m-disabled, .pf-m-aria-disabled) { + color: var(--pf-v5-global--danger-color--200); +} + +#containers-images .pf-v5-c-table.pf-m-compact .pf-v5-c-table__action { + --pf-v5-c-table__action--PaddingTop: 0.5rem; + --pf-v5-c-table__action--PaddingBottom: 0.5rem; +} + +.containers-images .pf-v5-c-expandable-section__content { + margin-block-start: 0; +} + +/* Override font-size due to h2 being wrapped in a Flex */ +.containers-images-title { + font-size: var(--pf-v5-global--FontSize--2xl); +} diff --git a/ui/cockpit-docker/src/Images.jsx b/ui/cockpit-docker/src/Images.jsx new file mode 100644 index 0000000..7f6b6a6 --- /dev/null +++ b/ui/cockpit-docker/src/Images.jsx @@ -0,0 +1,398 @@ +import React from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Card, CardBody, CardFooter, CardHeader, CardTitle } from "@patternfly/react-core/dist/esm/components/Card"; +import { DropdownItem } from '@patternfly/react-core/dist/esm/components/Dropdown/index.js'; +import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { ExpandableSection } from "@patternfly/react-core/dist/esm/components/ExpandableSection"; +import { Text, TextVariants } from "@patternfly/react-core/dist/esm/components/Text"; +import { cellWidth } from '@patternfly/react-table'; + +import cockpit from 'cockpit'; +import { ListingTable } from "cockpit-components-table.jsx"; +import { ListingPanel } from 'cockpit-components-listing-panel.jsx'; +import ImageDetails from './ImageDetails.jsx'; +import ImageHistory from './ImageHistory.jsx'; +import { ImageRunModal } from './ImageRunModal.jsx'; +import { ImageSearchModal } from './ImageSearchModal.jsx'; +import { ImageDeleteModal } from './ImageDeleteModal.jsx'; +import PruneUnusedImagesModal from './PruneUnusedImagesModal.jsx'; +import * as client from './client.js'; +import * as utils from './util.js'; +import { useDialogs, DialogsContext } from "dialogs.jsx"; + +import './Images.css'; +import '@patternfly/react-styles/css/utilities/Sizing/sizing.css'; + +import { KebabDropdown } from "cockpit-components-dropdown.jsx"; + +const _ = cockpit.gettext; + +class Images extends React.Component { + static contextType = DialogsContext; + + constructor(props) { + super(props); + this.state = { + intermediateOpened: false, + isExpanded: false, + }; + + this.downloadImage = this.downloadImage.bind(this); + this.renderRow = this.renderRow.bind(this); + } + + downloadImage(imageName, imageTag) { + let pullImageId = imageName; + if (!imageTag) + imageTag = "latest"; + + pullImageId += ":" + imageTag; + + this.setState({ imageDownloadInProgress: imageName }); + client.pullImage(pullImageId) + .then(() => { + this.setState({ imageDownloadInProgress: undefined }); + }) + .catch(ex => { + const error = cockpit.format(_("Failed to download image $0:$1"), imageName, imageTag || "latest"); + const errorDetail = ( +

{_("Error message")}: + {cockpit.format("$0 $1", ex.message, ex.reason)} +

+ ); + this.setState({ imageDownloadInProgress: undefined }); + this.props.onAddNotification({ type: 'danger', error, errorDetail }); + }); + } + + onOpenNewImagesDialog = () => { + const Dialogs = this.context; + Dialogs.show( + + ); + }; + + onOpenPruneUnusedImagesDialog = () => { + this.setState({ showPruneUnusedImagesModal: true }); + }; + + getUsedByText(image) { + const { imageContainerList } = this.props; + if (imageContainerList === null) { + return { title: _("unused"), count: 0 }; + } + const containers = imageContainerList[image.Id]; + if (containers !== undefined) { + const title = cockpit.format(cockpit.ngettext("$0 container", "$0 containers", containers.length), containers.length); + return { title, count: containers.length }; + } else { + return { title: _("unused"), count: 0 }; + } + } + + calculateStats = () => { + const { images, imageContainerList } = this.props; + const unusedImages = []; + const imageStats = { + imagesTotal: 0, + imagesSize: 0, + unusedTotal: 0, + unusedSize: 0, + }; + + if (imageContainerList === null) { + return { imageStats, unusedImages }; + } + + if (images !== null) { + Object.keys(images).forEach(id => { + const image = images[id]; + imageStats.imagesTotal += 1; + imageStats.imagesSize += image.Size; + + const usedBy = imageContainerList[image.Id]; + if (image.Containers === 0 || usedBy === undefined) { + imageStats.unusedTotal += 1; + imageStats.unusedSize += image.Size; + unusedImages.push(image); + } + }); + } + + return { imageStats, unusedImages }; + }; + + renderRow(image) { + const tabs = []; + const { title: usedByText, count: usedByCount } = this.getUsedByText(image); + + const columns = [ + { title: utils.image_name(image), header: true, props: { modifier: "breakWord" } }, + { title: utils.localize_time(image.Created), props: { className: "ignore-pixels" } }, + { title: utils.truncate_id(image.Id), props: { className: "ignore-pixels" } }, + { title: cockpit.format_bytes(image.Size), props: { className: "ignore-pixels", modifier: "nowrap" } }, + { title: {usedByText}, props: { className: "ignore-pixels", modifier: "nowrap" } }, + { + title: , + props: { className: 'pf-v5-c-table__action content-action' } + }, + ]; + + tabs.push({ + name: _("Details"), + renderer: ImageDetails, + data: { + image, + containers: this.props.imageContainerList !== null ? this.props.imageContainerList[image.Id] : null, + showAll: this.props.showAll, + } + }); + tabs.push({ + name: _("History"), + renderer: ImageHistory, + data: { + image, + } + }); + return { + expandedContent: , + columns, + props: { + key: image.Id, + "data-row-id": image.Id, + }, + }; + } + + render() { + const columnTitles = [ + { title: _("Image"), transforms: [cellWidth(20)] }, + { title: _("Created"), props: { className: "ignore-pixels", width: 15 } }, + { title: _("ID"), props: { className: "ignore-pixels" } }, + { title: _("Disk space"), props: { className: "ignore-pixels" } }, + { title: _("Used by"), props: { className: "ignore-pixels" } }, + ]; + let emptyCaption = _("No images"); + if (this.props.images === null) + emptyCaption = "Loading..."; + else if (this.props.textFilter.length > 0) + emptyCaption = _("No images that match the current filter"); + + const intermediateOpened = this.state.intermediateOpened; + + let filtered = []; + if (this.props.images !== null) { + filtered = Object.keys(this.props.images).filter(id => { + const tags = this.props.images[id].RepoTags || []; + if (!intermediateOpened && tags.length < 1) + return false; + if (this.props.textFilter.length > 0) + return tags.some(tag => tag.toLowerCase().indexOf(this.props.textFilter.toLowerCase()) >= 0); + return true; + }); + } + + filtered.sort((a, b) => { + const name_a = this.props.images[a].RepoTags.length > 0 ? this.props.images[a].RepoTags[0] : ""; + const name_b = this.props.images[b].RepoTags.length > 0 ? this.props.images[b].RepoTags[0] : ""; + if (name_a === "") + return 1; + if (name_b === "") + return -1; + return name_a > name_b ? 1 : -1; + }); + + const imageRows = filtered.map(id => this.renderRow(this.props.images[id])); + + const interim = this.props.images && Object.keys(this.props.images).some(id => { + // Intermediate image does not have any tags + if (this.props.images[id].RepoTags && this.props.images[id].RepoTags.length > 0) + return false; + + // Any text filter hides all images + if (this.props.textFilter.length > 0) + return false; + + return true; + }); + + let toggleIntermediate = ""; + if (interim) { + toggleIntermediate = ( + + + + ); + } + const cardBody = ( + <> + + {toggleIntermediate} + + ); + + const { imageStats, unusedImages } = this.calculateStats(); + const imageTitleStats = ( + <> + + {cockpit.format(cockpit.ngettext("$0 image total, $1", "$0 images total, $1", imageStats.imagesTotal), imageStats.imagesTotal, cockpit.format_bytes(imageStats.imagesSize))} + + {imageStats.unusedTotal !== 0 && + + {cockpit.format(cockpit.ngettext("$0 unused image, $1", "$0 unused images, $1", imageStats.unusedTotal), imageStats.unusedTotal, cockpit.format_bytes(imageStats.unusedSize))} + + } + + ); + + return ( + + + + + + + {_("Images")} + + {imageTitleStats} + + + + + + + + + {this.props.images && Object.keys(this.props.images).length + ? this.setState(prevState => ({ isExpanded: !prevState.isExpanded }))} + isExpanded={this.state.isExpanded}> + {cardBody} + + : cardBody} + + {/* The PruneUnusedImagesModal dialog needs to keep + * its list of unused images in sync with reality at + * all times since the API call will delete whatever + * is unused at the exact time of call, and the + * dialog better be showing the correct list of + * unused images at that time. Thus, we can't use + * Dialog.show for it but include it here in the + * DOM. */} + {this.state.showPruneUnusedImagesModal && + this.setState({ showPruneUnusedImagesModal: false })} + unusedImages={unusedImages} + onAddNotification={this.props.onAddNotification} /> } + {this.state.imageDownloadInProgress && +
{_("Pulling")} {this.state.imageDownloadInProgress}...
+
} +
+ ); + } +} + +const ImageOverActions = ({ handleDownloadNewImage, handlePruneUsedImages, unusedImages }) => { + const actions = [ + handleDownloadNewImage()} + > + {_("Download new image")} + , + handlePruneUsedImages()} + isDisabled={unusedImages.length === 0} + isAriaDisabled={unusedImages.length === 0} + > + {_("Prune unused images")} + + ]; + + return ( + + ); +}; + +const ImageActions = ({ image, onAddNotification }) => { + const Dialogs = useDialogs(); + + const runImage = () => { + Dialogs.show( + + {(dockerInfo) => ( + + {(Dialogs) => ( + + )} + + )} + ); + }; + + const removeImage = () => { + Dialogs.show(); + }; + + const runImageAction = ( + + ); + + const dropdownActions = [ + + {_("Create container")} + , + + {_("Delete")} + + ]; + + return ( + <> + {runImageAction} + + + ); +}; + +export default Images; diff --git a/ui/cockpit-docker/src/Notification.jsx b/ui/cockpit-docker/src/Notification.jsx new file mode 100644 index 0000000..3fc3ff2 --- /dev/null +++ b/ui/cockpit-docker/src/Notification.jsx @@ -0,0 +1,45 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2019 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ +import React from 'react'; +import { Alert, AlertActionCloseButton } from "@patternfly/react-core/dist/esm/components/Alert"; + +import cockpit from 'cockpit'; + +const _ = cockpit.gettext; + +let last_error = ""; + +function log_error_if_changed(error) { + // Put the error in the browser log, for easier debugging and + // matching of known issues in the integration tests. + if (error != last_error) { + last_error = error; + console.error(error); + } +} + +export const ErrorNotification = ({ errorMessage, errorDetail, onDismiss }) => { + log_error_if_changed(errorMessage + (errorDetail ? ": " + errorDetail : "")); + return ( + : null}> + { errorDetail &&

{_("Error message")}: {errorDetail}

} +
+ ); +}; diff --git a/ui/cockpit-docker/src/PruneUnusedContainersModal.jsx b/ui/cockpit-docker/src/PruneUnusedContainersModal.jsx new file mode 100644 index 0000000..263482d --- /dev/null +++ b/ui/cockpit-docker/src/PruneUnusedContainersModal.jsx @@ -0,0 +1,96 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import { SortByDirection } from "@patternfly/react-table"; +import cockpit from 'cockpit'; +import { ListingTable } from 'cockpit-components-table.jsx'; + +import * as client from './client.js'; +import * as utils from './util.js'; + +const _ = cockpit.gettext; + +const getContainerRow = (container, selected) => { + const columns = [ + { + title: container.name, + sortKey: container.name, + props: { width: 25, }, + }, + { + title: utils.localize_time(Date.parse(container.created) / 1000), + props: { width: 20, }, + }, + ]; + return { columns, selected, props: { key: container.id } }; +}; + +const PruneUnusedContainersModal = ({ close, unusedContainers, onAddNotification }) => { + const [isPruning, setPruning] = useState(false); + const [selectedContainerIds, setSelectedContainerIds] = React.useState(unusedContainers.map(u => u.id)); + + const handlePruneUnusedContainers = () => { + setPruning(true); + + const actions = []; + + for (const id of selectedContainerIds) { + if (id.endsWith("true")) { + actions.push(client.delContainer(true, id.replace(/true$/, ""), true)); + } else { + actions.push(client.delContainer(false, id.replace(/false$/, ""), true)); + } + } + Promise.all(actions).then(close) + .catch(ex => { + const error = _("Failed to prune unused containers"); + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + close(); + }); + }; + + const columns = [ + { title: _("Name"), sortable: true }, + { title: _("Created"), sortable: true }, + ]; + + const selectAllContainers = isSelecting => setSelectedContainerIds(isSelecting ? unusedContainers.map(c => c.id) : []); + const isContainerSelected = container => selectedContainerIds.includes(container.id); + const setContainerSelected = (container, isSelecting) => setSelectedContainerIds(prevSelected => { + const otherSelectedContainerName = prevSelected.filter(r => r !== container.id); + return isSelecting ? [...otherSelectedContainerName, container.id] : otherSelectedContainerName; + }); + + const onSelectContainer = (id, _rowIndex, isSelecting) => { + const container = unusedContainers.filter(u => u.id === id)[0]; + setContainerSelected(container, isSelecting); + }; + + return ( + + + + } + > +

{_("Removes selected non-running containers")}

+ onSelectContainer(rowData.props.id, rowIndex, isSelecting)} + onHeaderSelect={(_event, isSelecting) => selectAllContainers(isSelecting)} + id="unused-container-list" + rows={unusedContainers.map(container => getContainerRow(container, isContainerSelected(container))) } + variant="compact" sortBy={{ index: 0, direction: SortByDirection.asc }} /> +
+ ); +}; + +export default PruneUnusedContainersModal; diff --git a/ui/cockpit-docker/src/PruneUnusedImagesModal.jsx b/ui/cockpit-docker/src/PruneUnusedImagesModal.jsx new file mode 100644 index 0000000..3c46506 --- /dev/null +++ b/ui/cockpit-docker/src/PruneUnusedImagesModal.jsx @@ -0,0 +1,101 @@ +import React, { useState } from 'react'; +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox"; +import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex"; +import { List, ListItem } from "@patternfly/react-core/dist/esm/components/List"; +import { Modal } from "@patternfly/react-core/dist/esm/components/Modal"; +import cockpit from 'cockpit'; + +import * as client from './client.js'; +import * as utils from './util.js'; + +import "@patternfly/patternfly/utilities/Spacing/spacing.css"; + +const _ = cockpit.gettext; + +function ImageOptions({ images, checked, handleChange, name, showCheckbox }) { + const [isExpanded, onToggle] = useState(false); + let shownImages = images; + if (!isExpanded) { + shownImages = shownImages.slice(0, 5); + } + + if (shownImages.length === 0) { + return null; + } + const listNameId = "list-" + name; + + return ( + + {showCheckbox && + handleChange(val)} + aria-owns={listNameId} + /> + } + + {shownImages.map((image, index) => + + {utils.image_name(image)} + + )} + {!isExpanded && images.length > 5 && + + } + + + ); +} + +const PruneUnusedImagesModal = ({ close, unusedImages, onAddNotification }) => { + const [isPruning, setPruning] = useState(false); + const [deleteImages, setDeleteImages] = React.useState(true); + + const handlePruneUnusedImages = () => { + setPruning(true); + + client.pruneUnusedImages().then(close) + .catch(ex => { + const error = _("Failed to prune unused images"); + onAddNotification({ type: 'danger', error, errorDetail: ex.message }); + close(); + }); + }; + + const showCheckboxes = unusedImages.length > 0; + + return ( + + + + } + > + + + + + ); +}; + +export default PruneUnusedImagesModal; diff --git a/ui/cockpit-docker/src/PublishPort.jsx b/ui/cockpit-docker/src/PublishPort.jsx new file mode 100644 index 0000000..92a36cd --- /dev/null +++ b/ui/cockpit-docker/src/PublishPort.jsx @@ -0,0 +1,142 @@ +import React from 'react'; + +import { Button } from "@patternfly/react-core/dist/esm/components/Button"; +import { FormGroup } from "@patternfly/react-core/dist/esm/components/Form"; +import { FormSelect, FormSelectOption } from "@patternfly/react-core/dist/esm/components/FormSelect"; +import { Grid } from "@patternfly/react-core/dist/esm/layouts/Grid"; +import { TextInput } from "@patternfly/react-core/dist/esm/components/TextInput"; +import { Popover } from "@patternfly/react-core/dist/esm/components/Popover"; +import { OutlinedQuestionCircleIcon, TrashIcon } from '@patternfly/react-icons'; +import cockpit from 'cockpit'; +import ipaddr from "ipaddr.js"; + +import { FormHelper } from "cockpit-components-form-helper.jsx"; +import * as utils from './util.js'; + +const _ = cockpit.gettext; + +const MAX_PORT = 65535; + +export function validatePublishPort(value, key) { + switch (key) { + case "IP": + if (value && !ipaddr.isValid(value)) + return _("Must be a valid IP address"); + break; + case "hostPort": { + if (value) { + const hostPort = parseInt(value); + if (hostPort < 1 || hostPort > MAX_PORT) + return _("1 to 65535"); + } + + break; + } + case "containerPort": { + if (!value) + return _("Container port must not be empty"); + + const containerPort = parseInt(value); + if (containerPort < 1 || containerPort > MAX_PORT) + return _("1 to 65535"); + + break; + } + default: + console.error(`Unknown key "${key}"`); // not-covered: unreachable assertion + } +} + +export const PublishPort = ({ id, item, onChange, idx, removeitem, itemCount, validationFailed, onValidationChange }) => + ( + + + + + }> + { + utils.validationClear(validationFailed, "IP", onValidationChange); + utils.validationDebounce(() => onValidationChange({ ...validationFailed, IP: validatePublishPort(value, "IP") })); + onChange(idx, 'IP', value); + }} /> + + + + + + }> + { + utils.validationClear(validationFailed, "hostPort", onValidationChange); + utils.validationDebounce(() => onValidationChange({ ...validationFailed, hostPort: validatePublishPort(value, "hostPort") })); + onChange(idx, 'hostPort', value); + }} /> + + + + { + utils.validationClear(validationFailed, "containerPort", onValidationChange); + utils.validationDebounce(() => onValidationChange({ ...validationFailed, containerPort: validatePublishPort(value, "containerPort") })); + onChange(idx, 'containerPort', value); + }} /> + + + + onChange(idx, 'protocol', value)}> + + + + + + + + + + + ); + } + + if (this.state.serviceAvailable === null) // not detected yet + return ( + + + + {/* loading spinner */} + + + + + + ); + + if (!this.state.serviceAvailable) { + return ( + + + + } headingLevel="h2" /> + + this.setState({ enableService: checked }) } /> + + { cockpit.manifests.system && + + + + } + + + + + ); + } + + let imageContainerList = {}; + if (this.state.containers !== null) { + Object.keys(this.state.containers).forEach(c => { + const container = this.state.containers[c]; + const image = container.Image; + if (imageContainerList[image]) { + imageContainerList[image].push({ + container, + stats: this.state.containersStats[container.Id], + }); + } else { + imageContainerList[image] = [{ + container, + stats: this.state.containersStats[container.Id] + }]; + } + }); + } else + imageContainerList = null; + + let startService = ""; + const action = ( + <> + {_("Start")} + this.setState({ showStartService: false })} /> + + ); + if (!this.state.serviceAvailable && this.state.privileged) { + startService = ( + + ); + } + + const imageList = ( + this.setState({ containersFilter: "all" }) } + user={this.state.currentUser} + serviceAvailable={this.state.serviceAvailable} + /> + ); + const containerList = ( + + ); + + const notificationList = ( + + {this.state.notifications.map((notification, index) => { + return ( + this.onDismissNotification(notification.index)} />}> + {notification.errorDetail} + + ); + })} + + ); + + const contextInfo = { + cgroupVersion: this.state.cgroupVersion, + registries: this.state.registries, + selinuxAvailable: this.state.selinuxAvailable, + dockerRestartAvailable: this.state.dockerRestartAvailable, + version: this.state.version, + }; + + return ( + + + + {notificationList} + + + + + + { this.state.showStartService ? startService : null } + {imageList} + {containerList} + + + + + + ); + } +} + +export default Application; diff --git a/ui/cockpit-docker/src/client.js b/ui/cockpit-docker/src/client.js new file mode 100644 index 0000000..22d11ad --- /dev/null +++ b/ui/cockpit-docker/src/client.js @@ -0,0 +1,172 @@ +import rest from './rest.js'; + +const DOCKER_ADDRESS = "/var/run/docker.sock"; +export const VERSION = "/v1.43"; + +export function getAddress() { + return DOCKER_ADDRESS; +} + +function dockerCall(name, method, args, body) { + const options = { + method, + path: VERSION + name, + body: body || "", + params: args, + }; + + if (method === "POST" && body) + options.headers = { "Content-Type": "application/json" }; + + // console.log("dockerCall", options); + + return rest.call(getAddress(), options); +} + +const dockerJson = (name, method, args, body) => dockerCall(name, method, args, body) + .then(reply => JSON.parse(reply)); + +function dockerMonitor(name, method, args, callback) { + const options = { + method, + path: VERSION + name, + body: "", + params: args, + }; + + // console.log("dockerMonitor", options); + + const connection = rest.connect(getAddress()); + return connection.monitor(options, callback); +} + +export const streamEvents = (callback) => dockerMonitor("/events", "GET", {}, callback); + +export function getInfo() { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error("timeout")), 15000); + dockerJson("/info", "GET", {}) + .then(reply => resolve(reply)) + .catch(reject) + .finally(() => clearTimeout(timeout)); + }); +} + +export const getContainers = () => dockerJson("/containers/json", "GET", { all: true }); + +export const streamContainerStats = (id, callback) => dockerMonitor("/containers/" + id + "/stats", "GET", { stream: true }, callback); + +export function inspectContainer(id) { + const options = { + size: false // set true to display filesystem usage + }; + return dockerJson("/containers/" + id + "/json", "GET", options); +} + +export const delContainer = (id, force) => dockerCall("/containers/" + id, "DELETE", { force }); + +export const renameContainer = (id, config) => dockerCall("/containers/" + id + "/rename", "POST", config); + +export const createContainer = (config) => dockerJson("/containers/create", "POST", {}, JSON.stringify(config)); + +export const commitContainer = (commitData) => dockerCall("/commit", "POST", commitData); + +export const postContainer = (action, id, args) => dockerCall("/containers/" + id + "/" + action, "POST", args); + +export function execContainer(id) { + const args = { + AttachStderr: true, + AttachStdout: true, + AttachStdin: true, + Tty: true, + Cmd: ["/bin/sh"], + }; + + return dockerJson("/containers/" + id + "/exec", "POST", {}, JSON.stringify(args)); +} + +export function resizeContainersTTY(id, exec, width, height) { + const args = { + h: height, + w: width, + }; + + let point = "containers/"; + if (!exec) + point = "exec/"; + + console.log("resizeContainersTTY", point + id + "/resize", args); + return dockerCall("/" + point + id + "/resize", "POST", args); +} + +function parseImageInfo(info) { + const image = {}; + + if (info.Config) { + image.Entrypoint = info.Config.Entrypoint; + image.Command = info.Config.Cmd; + image.Ports = Object.keys(info.Config.ExposedPorts || {}); + image.Env = info.Config.Env; + } + image.Author = info.Author; + + return image; +} + +export function getImages(id) { + const options = {}; + if (id) + options.filters = JSON.stringify({ id: [id] }); + return dockerJson("/images/json", "GET", options) + .then(reply => { + const images = {}; + const promises = []; + + for (const image of reply) { + images[image.Id] = image; + promises.push(dockerJson("/images/" + image.Id + "/json", "GET", {})); + } + + return Promise.all(promises) + .then(replies => { + for (const info of replies) { + images[info.Id] = Object.assign(images[info.Id], parseImageInfo(info)); + } + return images; + }); + }); +} + +export const delImage = (id, force) => dockerJson("/images/" + id, "DELETE", { force }); + +export const untagImage = (id, repo, tag) => dockerCall("/images/" + id + "/untag", "POST", { repo, tag }); + +export function pullImage(reference) { + return new Promise((resolve, reject) => { + const options = { + fromImage: reference, + }; + dockerCall("/images/create", "POST", options) + .then(r => { + // Need to check the last response if it contains error + const responses = r.trim().split("\n"); + const response = JSON.parse(responses[responses.length - 1]); + if (response.error) { + response.message = response.error; + reject(response); + } else if (response.cause) // present for 400 and 500 errors + reject(response); + else + resolve(); + }) + .catch(reject); + }); +} + +export const pruneUnusedImages = () => dockerJson("/images/prune", "POST", {}); + +export const imageHistory = (id) => dockerJson(`/images/${id}/history`, "GET", {}); + +export const imageExists = (id) => dockerCall("/images/" + id + "/json", "GET", {}); + +export const containerExists = (id) => dockerCall("/containers/" + id + "/json", "GET", {}); diff --git a/ui/cockpit-docker/src/docker.scss b/ui/cockpit-docker/src/docker.scss new file mode 100644 index 0000000..6db864c --- /dev/null +++ b/ui/cockpit-docker/src/docker.scss @@ -0,0 +1,149 @@ +@use "ct-card.scss"; +@use "page.scss"; +@import "global-variables"; +// For pf-v5-line-clamp +@import "@patternfly/patternfly/sass-utilities/mixins.scss"; +// For pf-u-disabled-color-100 +@import "@patternfly/patternfly/utilities/Text/text.css"; + +#app .pf-v5-c-card.containers-containers, #app .pf-v5-c-card.containers-images { + @extend .ct-card; +} + +.pf-v5-c-modal-box__title-text { + white-space: break-spaces; +} + +#containers-images, #containers-containers { + // Decrease padding for the image/container toggle button list + .pf-v5-c-table.pf-m-compact .pf-v5-c-table__toggle { + padding-inline-start: 0; + } +} + +@media screen and (max-width: 768px) { + // Badges should not stretch in mobile mode + .pf-v5-c-table [data-label] > .pf-v5-c-badge { + justify-self: start; + } +} + +.container-block { + display: flex; + flex-direction: column; + word-break: break-all; +} + +.container-block small { + @include pf-v5-line-clamp("1"); + color: var(--pf-v5-global--Color--200); +} + +.container-name { + font-size: var(--pf-v5-global--FontSize--lg); + font-weight: 400; +} + +.containers-run-onbuildvarclaim input { + max-inline-size: 15em; +} + +.pf-v5-c-alert__description { + overflow-wrap: anywhere; +} + +.listing-action { + inline-size: 100%; + display: flex; + justify-content: space-around; +} + +.ct-badge-container-running, .ct-badge-pod-running { + background-color: var(--pf-v5-global--info-color--100); + color: white; +} + +.ct-badge-container-healthy { + background-color: var(--pf-v5-global--success-color--100); + color: white; +} + +.ct-badge-container-unhealthy { + background-color: var(--pf-v5-global--danger-color--100); + color: white; +} + +.ct-badge-toolbox { + background-color: var(--pf-v5-global--palette--purple-100); + color: var(--pf-v5-global--palette--purple-600); + + .pf-v5-theme-dark & { + background-color: var(--pf-v5-global--palette--purple-500); + color: white; + } +} + +.ct-badge-distrobox { + background-color: var(--pf-v5-global--palette--gold-100); + color: var(--pf-v5-global--palette--gold-600); + + .pf-v5-theme-dark & { + background-color: var(--pf-v5-global--palette--gold-500); + color: white; + } +} + +.green { + color: var(--pf-v5-global--success-color--100); +} + +.red { + color: var(--pf-v5-global--danger-color--100); +} + +// Hide the header nav from the expandable rows - this should be better done with JS but the current cockpit-listing-panel implementation does not support this variant +#containers-images .ct-listing-panel-head { + display: none; +} + +.ct-grey-text { + color: var(--pf-v5-global--Color--200); +} + +.content-action { + text-align: end; + white-space: nowrap !important; +} + +// Remove doubled-up padding and borders on nested tables in mobile +.ct-listing-panel-body .ct-table tr { + --pf-v5-c-table-tr--responsive--PaddingTop: 0; + --pf-v5-c-table-tr--responsive--PaddingRight: 0; + --pf-v5-c-table-tr--responsive--PaddingBottom: 0; + --pf-v5-c-table-tr--responsive--PaddingLeft: 0; +} + +@media (max-width: $pf-v5-global--breakpoint--md - 1) { + .show-only-when-wide { + display: none; + } +} + +@media (min-width: $pf-v5-global--breakpoint--md) { + .show-only-when-narrow { + display: none; + } + + // Add borders to no pod containers list and images list + .container-pod.pf-m-plain tbody, + .containers-images tbody { + border: var(--pf-v5-c-card--m-flat--BorderWidth) solid var(--pf-v5-c-card--m-flat--BorderColor); + } +} + +// Override table padding on mobile +@media (max-width: $pf-v5-global--breakpoint--md) { + .health-logs.pf-m-grid-md.pf-v5-c-table tr:where(.pf-v5-c-table__tr):not(.pf-v5-c-table__expandable-row) { + padding: 0; + } +} diff --git a/ui/cockpit-docker/src/index.html b/ui/cockpit-docker/src/index.html new file mode 100644 index 0000000..a0d703f --- /dev/null +++ b/ui/cockpit-docker/src/index.html @@ -0,0 +1,36 @@ + + + + + docker containers + + + + + + + + + + + + +
+
+ + diff --git a/ui/cockpit-docker/src/index.js b/ui/cockpit-docker/src/index.js new file mode 100644 index 0000000..7d8bc18 --- /dev/null +++ b/ui/cockpit-docker/src/index.js @@ -0,0 +1,30 @@ +/* + * This file is part of Cockpit. + * + * Copyright (C) 2017 Red Hat, Inc. + * + * Cockpit is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * Cockpit is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Cockpit; If not, see . + */ + +import "cockpit-dark-theme"; +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import 'patternfly/patternfly-5-cockpit.scss'; +import Application from './app.jsx'; +import './docker.scss'; + +document.addEventListener("DOMContentLoaded", function () { + const root = createRoot(document.getElementById('app')); + root.render(); +}); diff --git a/ui/cockpit-docker/src/manifest.json b/ui/cockpit-docker/src/manifest.json new file mode 100644 index 0000000..6f0aec2 --- /dev/null +++ b/ui/cockpit-docker/src/manifest.json @@ -0,0 +1,16 @@ +{ + "conditions": [ + {"path-exists": "/lib/systemd/system/docker.socket"} + ], + "menu": { + "index": { + "label": "Docker containers", + "order": 50, + "keywords": [ + { + "matches": ["docker", "container", "image"] + } + ] + } + } +} diff --git a/ui/cockpit-docker/src/rest.js b/ui/cockpit-docker/src/rest.js new file mode 100644 index 0000000..5f07c29 --- /dev/null +++ b/ui/cockpit-docker/src/rest.js @@ -0,0 +1,100 @@ +import cockpit from "cockpit"; +import { debug } from "./util.js"; + +function manage_error(reject, error, content) { + let content_o = {}; + if (content) { + try { + content_o = JSON.parse(content); + } catch { + content_o.message = content; + } + } + const c = { ...error, ...content_o }; + reject(c); +} + +// calls are async, so keep track of a call counter to associate a result with a call +let call_id = 0; + +function connect(address) { + /* This doesn't create a channel until a request */ + const http = cockpit.http(address, { superuser: null }); + const connection = {}; + + connection.monitor = function(options, callback, return_raw) { + return new Promise((resolve, reject) => { + let buffer = ""; + + http.request(options) + .stream(data => { + if (return_raw) + callback(data); + else { + buffer += data; + const chunks = buffer.split("\n"); + buffer = chunks.pop(); + + chunks.forEach(chunk => { + debug("monitor", chunk); + callback(JSON.parse(chunk)); + }); + } + }) + .catch((error, content) => { + manage_error(reject, error, content); + }) + .then(resolve); + }); + }; + + connection.call = function (options) { + const id = call_id++; + debug(`call ${id}:`, JSON.stringify(options)); + return new Promise((resolve, reject) => { + options = options || {}; + http.request(options) + .then(result => { + debug(`call ${id} result:`, JSON.stringify(result)); + resolve(result); + }) + .catch((error, content) => { + debug(`call ${id} error:`, JSON.stringify(error), "content", JSON.stringify(content)); + manage_error(reject, error, content); + }); + }); + }; + + connection.close = function () { + http.close(); + }; + + return connection; +} + +/* + * Connects to the docker service, performs a single call, and closes the + * connection. + */ +async function call (address, parameters) { + const connection = connect(address); + const result = await connection.call(parameters); + connection.close(); + // if (parameters.method === "GET") + // return result; + + // let p = {}; + // try { + // p = JSON.parse(result); + // } catch { + // p = result; + // } + // console.log("call", { method: parameters.method, path: parameters.path, parameters, result: p }); + + return result; +} + +export default { + connect, + call +}; diff --git a/ui/cockpit-docker/src/util.js b/ui/cockpit-docker/src/util.js new file mode 100644 index 0000000..deff036 --- /dev/null +++ b/ui/cockpit-docker/src/util.js @@ -0,0 +1,214 @@ +import React, { useContext } from "react"; + +import cockpit from 'cockpit'; + +import { debounce } from 'throttle-debounce'; +import * as dfnlocales from 'date-fns/locale'; +import { formatRelative } from 'date-fns'; +const _ = cockpit.gettext; + +export const DockerInfoContext = React.createContext(); +export const useDockerInfo = () => useContext(DockerInfoContext); + +export const WithDockerInfo = ({ value, children }) => { + return ( + + {children} + + ); +}; + +// https://github.com/containers/podman/blob/main/libpod/define/containerstate.go +// "Restarting" comes from special handling of restart case in Application.updateContainer() +export const states = [_("Exited"), _("Paused"), _("Stopped"), _("Removing"), _("Configured"), _("Created"), _("Restart"), _("Running")]; + +export const fallbackRegistries = ["docker.io", "quay.io"]; + +export function debug(...args) { + if (window.debugging === "all" || window.debugging?.includes("docker")) + console.debug("docker", ...args); +} + +export function truncate_id(id) { + if (!id) { + return ""; + } + + if (id.indexOf(":") !== -1) + id = id.split(":")[1]; + + return id.substr(0, 12); +} + +export function localize_time(unix_timestamp) { + if (unix_timestamp === undefined || isNaN(unix_timestamp)) + return ""; + const locale = (cockpit.language == "en") ? dfnlocales.enUS : dfnlocales[cockpit.language.replace('_', '')]; + return formatRelative(unix_timestamp * 1000, Date.now(), { locale }); +} + +export function format_cpu_usage(stats) { + const cpu_usage = stats?.cpu_stats?.cpu_usage?.total_usage; + const system_cpu_usage = stats?.cpu_stats?.system_cpu_usage; + const precpu_usage = stats?.precpu_stats?.cpu_usage?.total_usage; + const precpu_system_cpu_usage = stats?.precpu_stats?.system_cpu_usage; + + if (cpu_usage === undefined || isNaN(cpu_usage)) + return ""; + + let cpu_percent = 0; + if (precpu_usage !== undefined && precpu_system_cpu_usage !== undefined) { + const cpu_delta = cpu_usage - precpu_usage; + const system_delta = system_cpu_usage - precpu_system_cpu_usage; + if (system_delta > 0 && cpu_delta > 0) + cpu_percent = (cpu_delta / system_delta) * stats.cpu_stats.online_cpus * 100; + } + + return [cpu_percent.toFixed(2) + "%", cpu_percent]; +} + +export function format_memory_and_limit(stats) { + const usage = stats?.memory_stats?.usage; + const limit = stats?.memory_stats?.limit; + + if (usage === undefined || isNaN(usage)) + return ""; + + let mtext = ""; + let unit; + let parts; + if (limit) { + parts = cockpit.format_bytes(limit, undefined, { separate: true }); + mtext = " / " + parts.join(" "); + unit = parts[1]; + } + + if (usage) { + parts = cockpit.format_bytes(usage, unit, { separate: true }); + if (mtext) + return [_(parts[0] + mtext), usage]; + else + return [_(parts.join(" ")), usage]; + } else { + return ["", -1]; + } +} + +/* + * The functions quote_cmdline and unquote_cmdline implement + * a simple shell-like quoting syntax. They are used when letting the + * user edit a sequence of words as a single string. + * + * When parsing, words are separated by whitespace. Single and double + * quotes can be used to protect a sequence of characters that + * contains whitespace or the other quote character. A backslash can + * be used to protect any character. Quotes can appear in the middle + * of a word. + */ + +export function quote_cmdline(words) { + words = words || []; + + if (typeof words === 'string') + words = words.split(' '); + + function is_whitespace(c) { + return c == ' '; + } + + function quote(word) { + let text = ""; + let quote_char = ""; + let i; + for (i = 0; i < word.length; i++) { + if (word[i] == '\\' || word[i] == quote_char) + text += '\\'; + else if (quote_char === "") { + if (word[i] == "'" || is_whitespace(word[i])) + quote_char = '"'; + else if (word[i] == '"') + quote_char = "'"; + } + text += word[i]; + } + + return quote_char + text + quote_char; + } + + return words.map(quote).join(' '); +} + +export function unquote_cmdline(text) { + const words = []; + let next; + + function is_whitespace(c) { + return c == ' '; + } + + function skip_whitespace() { + while (next < text.length && is_whitespace(text[next])) + next++; + } + + function parse_word() { + let word = ""; + let quote_char = null; + + while (next < text.length) { + if (text[next] == '\\') { + next++; + if (next < text.length) { + word += text[next]; + } + } else if (text[next] == quote_char) { + quote_char = null; + } else if (quote_char) { + word += text[next]; + } else if (text[next] == '"' || text[next] == "'") { + quote_char = text[next]; + } else if (is_whitespace(text[next])) { + break; + } else + word += text[next]; + next++; + } + return word; + } + + next = 0; + skip_whitespace(); + while (next < text.length) { + words.push(parse_word()); + skip_whitespace(); + } + + return words; +} + +export function image_name(image) { + return image.RepoTags.length > 0 ? image.RepoTags[0] : ":"; +} + +export function is_valid_container_name(name) { + return /^[a-zA-Z0-9][a-zA-Z0-9_\\.-]*$/.test(name); +} + +/* Clears a single field in validationFailed object. + * + * Arguments: + * - validationFailed (object): Object containing list of fields with validation error + * - key (string): Specified which field from validationFailed object is clear + * - onValidationChange (func) + */ +export const validationClear = (validationFailed, key, onValidationChange) => { + if (!validationFailed) + return; + + const delta = { ...validationFailed }; + delete delta[key]; + onValidationChange(delta); +}; + +// This method needs to be outside of component as re-render would create a new instance of debounce +export const validationDebounce = debounce(500, (validationHandler) => validationHandler()); diff --git a/ui/cockpit-docker/test/browser/browser.sh b/ui/cockpit-docker/test/browser/browser.sh new file mode 100755 index 0000000..b612914 --- /dev/null +++ b/ui/cockpit-docker/test/browser/browser.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +set -eux +cd "${0%/*}/../.." + +# HACK: ensure that critical components are up to date: https://github.com/psss/tmt/issues/682 +dnf update -y docker crun conmon criu + +# if we run during cross-project testing against our main-builds COPR, then let that win +# even if Fedora has a newer revision +main_builds_repo="$(ls /etc/yum.repos.d/*cockpit*main-builds* 2>/dev/null || true)" +if [ -n "$main_builds_repo" ]; then + echo 'priority=0' >> "$main_builds_repo" + dnf distro-sync -y --repo 'copr*' cockpit-docker +fi + +# Show critical package versions +rpm -q runc crun docker criu passt kernel-core selinux-policy cockpit-docker cockpit-bridge || true + +# Show network information, for pasta debugging +ip address show +ip -4 route show +ip -6 route show + +# allow test to set up things on the machine +mkdir -p /root/.ssh +curl https://raw.githubusercontent.com/cockpit-project/bots/main/machine/identity.pub >> /root/.ssh/authorized_keys +chmod 600 /root/.ssh/authorized_keys + +# create user account for logging in +if ! id admin 2>/dev/null; then + useradd -c Administrator -G wheel admin + echo admin:foobar | chpasswd +fi + +# set root's password +echo root:foobar | chpasswd + +# avoid sudo lecture during tests +su -c 'echo foobar | sudo --stdin whoami' - admin + +# disable core dumps, we rather investigate them upstream where test VMs are accessible +echo core > /proc/sys/kernel/core_pattern + +# grab a few images to play with; tests run offline, so they cannot download images +docker rmi --all + +# set up our expected images, in the same way that we do for upstream CI +# this sometimes runs into network issues, so retry a few times +for retry in $(seq 5); do + if curl https://raw.githubusercontent.com/cockpit-project/bots/main/images/scripts/lib/podman-images.setup | sh -eux; then + break + fi + sleep $((5 * retry * retry)) +done + +CONTAINER="$(cat .cockpit-ci/container)" + +# import the test CONTAINER image as a directory tree for nspawn +mkdir /var/tmp/tasks +podman export "$(podman create --name tasks-import $CONTAINER)" | tar -x -C /var/tmp/tasks +podman rm tasks-import +podman rmi $CONTAINER + +# image setup, shared with upstream tests +sh -x test/vm.install + +systemctl enable --now cockpit.socket docker.socket + +# Run tests in the cockpit tasks container, as unprivileged user +# Use nspawn to avoid the tests killing the tasks container itself +chown -R 1111:1111 "${TMT_TEST_DATA}" . + +SYSTEMD_SECCOMP=0 systemd-nspawn \ + -D /var/tmp/tasks/ \ + --ephemeral \ + --user user \ + --setenv=TEST_AUDIT_NO_SELINUX="${TEST_AUDIT_NO_SELINUX:-}" \ + --bind="${TMT_TEST_DATA}":/logs --setenv=LOGS=/logs \ + --bind="$(pwd)":/source --setenv=SOURCE=/source \ + --bind-ro=/usr/lib/os-release:/run/host/usr/lib/os-release \ + sh /source/test/browser/run-test.sh "$@" diff --git a/ui/cockpit-docker/test/browser/main.fmf b/ui/cockpit-docker/test/browser/main.fmf new file mode 100644 index 0000000..8d12fe4 --- /dev/null +++ b/ui/cockpit-docker/test/browser/main.fmf @@ -0,0 +1,20 @@ +require: + - cockpit-docker + - cockpit-ws + - cockpit-system + - criu + # HACK: https://bugzilla.redhat.com/show_bug.cgi?id=2269485 + - slirp4netns +duration: 30m + +/system: + test: ./browser.sh system + summary: Run *System tests + +/user: + test: ./browser.sh user + summary: Run *User tests + +/other: + test: ./browser.sh other + summary: Run all other tests diff --git a/ui/cockpit-docker/test/browser/run-test.sh b/ui/cockpit-docker/test/browser/run-test.sh new file mode 100644 index 0000000..fe794b2 --- /dev/null +++ b/ui/cockpit-docker/test/browser/run-test.sh @@ -0,0 +1,54 @@ +set -eux + +PLAN="$1" + +cd "${SOURCE}" + +# tests need cockpit's bots/ libraries and test infrastructure +rm -f bots # common local case: existing bots symlink +make bots test/common + +if [ -e .git ]; then + tools/node-modules checkout + # disable detection of affected tests; testing takes too long as there is no parallelization + mv .git dot-git +else + # upstream tarballs ship test dependencies; print version for debugging + grep '"version"' node_modules/chrome-remote-interface/package.json +fi + +. /run/host/usr/lib/os-release +export TEST_OS="${ID}-${VERSION_ID/./-}" + +if [ "$TEST_OS" = "centos-8" ] || [ "$TEST_OS" = "centos-9" ]; then + TEST_OS="${TEST_OS}-stream" +fi + +# Chromium sometimes gets OOM killed on testing farm +export TEST_BROWSER=firefox + +# select subset of tests according to plan +TESTS="$(test/common/run-tests -l)" +case "$PLAN" in + system) TESTS="$(echo "$TESTS" | grep 'System$')" ;; + user) TESTS="$(echo "$TESTS" | grep 'User$')" ;; + other) TESTS="$(echo "$TESTS" | grep -vE '(System|User)$')" ;; + *) echo "Unknown test plan: $PLAN" >&2; exit 1 ;; +esac + +EXCLUDES="" + +# make it easy to check in logs +echo "TEST_ALLOW_JOURNAL_MESSAGES: ${TEST_ALLOW_JOURNAL_MESSAGES:-}" +echo "TEST_AUDIT_NO_SELINUX: ${TEST_AUDIT_NO_SELINUX:-}" + +RC=0 +./test/common/run-tests \ + --nondestructive \ + --machine localhost:22 \ + --browser localhost:9090 \ + $TESTS \ + $EXCLUDES \ +|| RC=$? +cp --verbose Test* "$LOGS" || true +exit $RC diff --git a/ui/cockpit-docker/test/check-application b/ui/cockpit-docker/test/check-application new file mode 100755 index 0000000..9525ab0 --- /dev/null +++ b/ui/cockpit-docker/test/check-application @@ -0,0 +1,2714 @@ +#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/common/pywrap", sys.argv) +# Run this with --help to see available options for tracing and debugging +# See https://github.com/cockpit-project/cockpit/blob/main/test/common/testlib.py +# "class Browser" and "class MachineCase" for the available API. + +import os +import sys +import time + +import testlib +from machine.machine_core import ssh_connection + +REGISTRIES_CONF = """ +[registries.search] +registries = ['localhost:5000', 'localhost:6000'] + +[registries.insecure] +registries = ['localhost:5000', 'localhost:6000'] +""" + +NOT_RUNNING = ["Exited", "Stopped"] + +# image names used in tests +IMG_ALPINE = "localhost/test-alpine" +IMG_ALPINE_LATEST = IMG_ALPINE + ":latest" +IMG_BUSYBOX = "localhost/test-busybox" +IMG_BUSYBOX_LATEST = IMG_BUSYBOX + ":latest" +IMG_REGISTRY = "localhost/test-registry" +IMG_REGISTRY_LATEST = IMG_REGISTRY + ":latest" + + +def docker_version(cls): + version = cls.execute(False, "docker -v").strip().split(' ')[-1] + # HACK: handle possible rc versions such as 4.4.0-rc2 + return tuple(int(v.split('-')[0]) for v in version.split('.')) + + +def showImages(browser): + if browser.attr("#containers-images button.pf-v5-c-expandable-section__toggle", "aria-expanded") == 'false': + browser.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + +def checkImage(browser, name, owner): + showImages(browser) + browser.wait_visible("#containers-images table") + browser.wait_js_func("""(function (first, last) { + let items = ph_select("#containers-images table tbody"); + for (i = 0; i < items.length; i++) + if (items[i].innerText.trim().startsWith(first) && items[i].innerText.trim().includes(last)) + return true; + return false; + })""", name, owner) + + +@testlib.nondestructive +class TestApplication(testlib.MachineCase): + + def setUp(self): + super().setUp() + m = self.machine + m.execute(""" + systemctl stop docker.service; systemctl stop containerd.service; systemctl --now enable docker.socket + # Ensure docker is really stopped, otherwise it keeps the containers/ directory busy + pkill -e -9 docker || true + while pgrep docker; do sleep 0.1; done + pkill -e -9 containerd || true + while pgrep containerd; do sleep 0.1; done + findmnt --list -otarget | grep /var/lib/docker/. | xargs -r umount + sync + """) + + # backup/restore pristine docker state, so that tests can run on existing testbeds + self.restore_dir("/var/lib/docker") + + # HACK: sometimes docker leaks mounts + self.addCleanup(m.execute, """ + systemctl stop docker.service containerd.service docker.socket + + systemctl reset-failed docker.service docker.socket + docker system reset --force + pkill -e -9 docker || true + while pgrep docker; do sleep 0.1; done + pkill -e -9 containerd || true + while pgrep containerd; do sleep 0.1; done + + # HACK: sometimes docker leaks mounts + findmnt --list -otarget | grep /var/lib/docker/. | xargs -r umount + sync + """) + + # Create admin session + m.execute(""" + if [ ! -d /home/admin/.ssh ]; then + mkdir /home/admin/.ssh + cp /root/.ssh/* /home/admin/.ssh + chown -R admin:admin /home/admin/.ssh + chmod -R go-wx /home/admin/.ssh + fi + """) + self.admin_s = ssh_connection.SSHConnection(user="admin", + address=m.ssh_address, + ssh_port=m.ssh_port, + identity_file=m.identity_file) + + # HACK: system reset has 10s timeout, make that faster with an extra `stop` + # https://github.com/containers/podman/issues/21874 + # Ubuntu 22.04 has old podman that does not know about rm --time + if m.image == 'ubuntu-2204': + self.addCleanup(self.admin_s.execute, "docker rm --force --all", timeout=300) + self.addCleanup(self.admin_s.execute, "docker pod rm --force --all", timeout=300) + else: + self.addCleanup(self.admin_s.execute, "docker rm --force --time 0 --all") + self.addCleanup(self.admin_s.execute, "docker pod rm --force --time 0 --all") + + # But disable it globally so that "systemctl --user disable" does what we expect + m.execute("systemctl --global disable docker.socket") + + self.allow_journal_messages("/run.*/docker/docker: couldn't connect.*") + self.allow_journal_messages(".*/run.*/docker/docker.*Connection reset by peer") + + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1008249 + self.has_criu = "debian" not in m.image and "ubuntu" not in m.image + self.has_selinux = "arch" not in m.image and "debian" not in m.image and "ubuntu" not in m.image + self.has_cgroupsV2 = m.image not in ["centos-8-stream"] and not m.image.startswith('rhel-8') + + self.system_images_count = int(self.execute(True, "docker images -n | wc -l").strip()) + self.user_images_count = int(self.execute(False, "docker images -n | wc -l").strip()) + + # allow console.error + self.allow_browser_errors( + ".*couldn't search registry \".*\": pinging container registry .*", + ".*Error occurred while connecting console: cannot resize session: cannot resize container.*", + ) + + def tearDown(self): + if self.getError(): + # dump container logs for debugging + for auth in [False, True]: + print(f"----- {'system' if auth else 'user'} containers -----", file=sys.stderr) + self.execute(auth, "docker ps -a >&2") + self.execute(auth, 'for c in $(docker ps -aq); do echo "---- $c ----" >&2; docker logs $c >&2; done') + + super().tearDown() + + def getRestartPolicy(self, auth, container_name): + cmd = f"docker inspect --format '{{{{.HostConfig.RestartPolicy}}}}' {container_name}" + return self.execute(auth, cmd).strip() + + def waitNumImages(self, expected): + self.browser.wait_js_func("ph_count_check", "#containers-images table[aria-label='Images'] > tbody", expected) + + def waitNumContainers(self, expected, auth): + if auth and self.machine.ostree_image: + extra = 1 # cockpit/ws + else: + extra = 0 + + self.browser.wait_js_func("ph_count_check", "#containers-containers tbody", expected + extra) + + def performContainerAction(self, container, cmd): + b = self.browser + b.click(f"#containers-containers tbody tr:contains('{container}') .pf-v5-c-menu-toggle") + b.click(f"#containers-containers tbody tr:contains('{container}') button.pf-v5-c-menu__item:contains({cmd})") + + def getContainerAction(self, container, cmd): + return f"#containers-containers tbody tr:contains('{container}') button.pf-v5-c-menu__item:contains({cmd})" + + def toggleExpandedContainer(self, container): + b = self.browser + b.click(f"#containers-containers tbody tr:contains('{container}') .pf-v5-c-table__toggle button") + + def getContainerAttr(self, container, key, selector=""): + b = self.browser + return b.text(f"#containers-containers tbody tr:contains('{container}') > td[data-label={key}] {selector}") + + def execute(self, system, cmd): + if system: + return self.machine.execute(cmd) + else: + return self.admin_s.execute(cmd) + + def login(self, system=True): + # HACK: The first rootless call often gets stuck or fails + # In such case we have alert banner to start the service (or just empty state) + # A real user would just hit the button so lets do the same as this is always getting + # back to us and we waste too much time reporting to docker with mixed results. + # Examples: + # https://github.com/containers/docker/issues/8762 + # https://github.com/containers/docker/issues/9251 + # https://github.com/containers/docker/issues/6660 + + b = self.browser + + self.login_and_go("/docker", superuser=system) + b.wait_visible("#app") + + with self.browser.wait_timeout(30): + try: + b.wait_not_in_text("#containers-containers", "Loading") + b.wait_not_present("#overview div.pf-v5-c-alert") + except testlib.Error: + if system: + b.click("#overview div.pf-v5-c-alert .pf-v5-c-alert__action > button:contains(Start)") + b.wait_not_present("#overview div.pf-v5-c-alert") + else: + b.click("#app .pf-v5-c-empty-state button.pf-m-primary") + b.wait_not_present("#app .pf-v5-c-empty-state button") + + def waitPodRow(self, podName, present=False): + if present: + self.browser.wait_visible("#table-" + podName) + else: + self.browser.wait_not_present("#table-" + podName) + + def waitPodContainer(self, podName, containerList, system=True): + if len(containerList): + for container in containerList: + self.waitContainer(container["id"], system, name=container["name"], image=container["image"], + cmd=container["command"], state=container["state"], pod=podName) + else: + if self.browser.val("#containers-containers-filter") == "all": + self.browser.wait_in_text("#table-" + podName + " .pf-v5-c-empty-state", "No containers in this pod") + else: + self.browser.wait_in_text("#table-" + podName + " .pf-v5-c-empty-state", + "No running containers in this pod") + + def waitContainerRow(self, container, present=True): + b = self.browser + if present: + b.wait_visible(f'#containers-containers td[data-label="Container"]:contains("{container}")') + else: + b.wait_not_present(f'#containers-containers td[data-label="Container"]:contains("{container}")') + + def performPodAction(self, podName, podOwner, action): + b = self.browser + + b.click(f"#pod-{podName}-{podOwner}-action-toggle") + b.click(f"ul.pf-v5-c-menu__list li > button.pod-action-{action.lower()}") + b.wait_not_present("ul.pf-v5-c-menu__list") + + def getStartTime(self, container: str, *, auth: bool) -> str: + # don't format the raw time strings from the API, force json format + out = self.execute(auth, "docker inspect --format '{{json .State.StartedAt}}' " + container) + return out.strip().replace('"', '') + + def waitRestart(self, container: str, old_start: str, *, auth: bool) -> int: + for _ in range(10): + new_start = self.getStartTime(container, auth=auth) + if new_start > old_start: + return new_start + time.sleep(1) + else: + self.fail("Timed out waiting for StartedAt change") + + # def testPods(self): + # b = self.browser + + # self.login() + + # self.filter_containers("running") + # if not self.machine.ostree_image: + # b.wait_in_text("#containers-containers", "No running containers") + + # # Run a pods as system + # self.machine.execute("docker pod create --infra=false --name pod-1") + + # self.waitPodRow("pod-1", False) + # self.filter_containers("all") + # self.waitPodContainer("pod-1", []) + + # def get_pod_cpu_usage(pod_name): + # cpu = self.browser.text(f"#table-{pod_name}-title .pod-cpu") + # self.assertIn('%', cpu) + # return float(cpu[:-1]) + + # def get_pod_memory(pod_name): + # memory = self.browser.text(f"#table-{pod_name}-title .pod-memory") + # try: + # value, unit = memory.split(' ') + # self.assertIn(unit, ["GB", "MB", "kB", "B"]) + # return float(value) + # except ValueError: + # # no unit → only for 0 or not initialized yet + # self.assertIn(memory, ["0", ""]) + # return 0 + + # run_cmd = f"docker run -d --pod pod-1 --name test-pod-1-system --stop-timeout 0 {IMG_ALPINE} sleep 100" + # containerId = self.machine.execute(run_cmd).strip() + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Running", "id": containerId}]) + # cpu = get_pod_cpu_usage("pod-1") + # b.wait(lambda: get_pod_memory("pod-1") > 0) + + # # Test that cpu usage increases + # self.machine.execute("docker exec -di test-pod-1-system sh -c 'dd bs=1024 < /dev/urandom > /dev/null'") + # b.wait(lambda: get_pod_cpu_usage("pod-1") > cpu) + + # self.machine.execute("docker pod stop -t0 pod-1") # disable timeout, so test doesn't wait endlessly + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": NOT_RUNNING, "id": containerId}]) + # self.filter_containers("running") + # self.waitPodRow("pod-1", False) + + # self.filter_containers("all") + # b.set_input_text('#containers-filter', 'pod-1') + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": NOT_RUNNING, "id": containerId}]) + # b.set_input_text('#containers-filter', 'test-pod-1-system') + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": NOT_RUNNING, "id": containerId}]) + # # TODO add pixel test when this is again reachable - https://github.com/cockpit-project/bots/issues/2463 + + # # Check Pod Actions + # self.performPodAction("pod-1", "system", "Start") + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Running", "id": containerId}]) + + # self.performPodAction("pod-1", "system", "Pause") + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Paused", "id": containerId}]) + + # self.performPodAction("pod-1", "system", "Unpause") + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Running", "id": containerId}]) + + # self.performPodAction("pod-1", "system", "Stop") + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": NOT_RUNNING, "id": containerId}]) + + # self.machine.execute("docker pod start pod-1") + # self.waitPodContainer("pod-1", [{"name": "test-pod-1-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Running", "id": containerId}]) + + # old_start = self.getStartTime("test-pod-1-system", auth=True) + # self.performPodAction("pod-1", "system", "Restart") + # self.waitRestart("test-pod-1-system", old_start, auth=True) + + # self.performPodAction("pod-1", "system", "Delete") + # b.click(".pf-v5-c-modal-box button:contains(Delete)") + # # Alert should be shown, that running pods need to be force deleted. + # b.wait_in_text(".pf-v5-c-modal-box__body .pf-v5-c-list", "test-pod-1-system") + # b.click(".pf-v5-c-modal-box button:contains('Force delete')") + # self.waitPodRow("pod-1", False) + + # HACK: there is some race here which steals the focus from the filter input and selects the page text instead + # for _ in range(3): + # b.focus('#containers-filter') + # time.sleep(1) + # if b.eval_js('document.activeElement == document.querySelector("#containers-filter")'): + # break + # b.set_input_text('#containers-filter', '') + # self.machine.execute("podman pod create --infra=false --name pod-2") + # self.waitPodContainer("pod-2", []) + # run_cmd = f"podman run -d --pod pod-2 --name test-pod-2-system --stop-timeout 0 {IMG_ALPINE} sleep 100" + # containerId = self.machine.execute(run_cmd).strip() + # self.waitPodContainer("pod-2", [{"name": "test-pod-2-system", "image": IMG_ALPINE, + # "command": "sleep 100", "state": "Running", "id": containerId}]) + # self.machine.execute("podman rm --force -t0 test-pod-2-system") + # self.waitPodContainer("pod-2", []) + # self.performPodAction("pod-2", "system", "Delete") + # b.wait_not_in_text(".pf-v5-c-modal-box__body", "test-pod-2-system") + # b.click(".pf-v5-c-modal-box button:contains('Delete')") + # self.waitPodRow("pod-2", False) + + # # Volumes / mounts + # self.machine.execute("docker pod create -p 9999:9999 -v /tmp:/app --name pod-3") + # self.machine.execute("docker pod start pod-3") + + # self.waitPodContainer("pod-3", []) + # # Verify 1 port mapping + # b.wait_in_text("#table-pod-3-title .pod-details-ports-btn", "1") + # b.click("#table-pod-3-title .pod-details-ports-btn") + # b.wait_in_text(".pf-v5-c-popover__content", "0.0.0.0:9999 → 9999/tcp") + # # Verify 1 mount + # b.wait_in_text("#table-pod-3-title .pod-details-volumes-btn", "1") + # b.click("#table-pod-3-title .pod-details-volumes-btn") + # b.wait_in_text(".pf-v5-c-popover__content", "/tmp ↔ /app") + + def testBasicSystem(self): + self._testBasic(True) + + b = self.browser + + # Test dropping and gaining privileges + b.set_val("#containers-containers-owner", "all") + self.filter_containers("all") + self.execute(False, "docker pod create --infra=false --name pod_user") + self.execute(True, "docker pod create --infra=false --name pod_system") + + checkImage(b, IMG_REGISTRY, "system") + checkImage(b, IMG_REGISTRY, "admin") + b.wait_visible("#containers-containers .pod-name:contains('pod_user')") + b.wait_visible("#containers-containers .pod-name:contains('pod_system')") + b.wait_visible("#containers-containers .container-name:contains('a')") + b.wait_visible("#containers-containers .container-name:contains('b')") + + # Drop privileges - all system things should disappear + b.drop_superuser() + b.wait_not_present("#containers-containers .pod-name:contains('pod_system')") + b.wait_not_present("#containers-containers .container-name:contains('a')") + b.wait_visible("#containers-containers .pod-name:contains('pod_user')") + b.wait_visible("#containers-containers .container-name:contains('b')") + # Checking images is harder but if there would be more than one this would fail + b.wait_visible(f"#containers-images:contains('{IMG_REGISTRY}')") + + # Owner select should disappear + b.wait_not_present("#containers-containers-owner") + + # Also user selection in image download should not be visible + b.click("#image-actions-dropdown") + b.click("button:contains(Download new image)") + + b.wait_visible('div.pf-v5-c-modal-box header:contains("Search for an image")') + b.wait_visible("div.pf-v5-c-modal-box footer button:contains(Download):disabled") + b.wait_not_present("#as-user") + b.click(".pf-v5-c-modal-box button:contains('Cancel')") + b.wait_not_present('div.pf-v5-c-modal-box header:contains("Search for an image")') + + # Gain privileges + b.become_superuser(passwordless=self.machine.image == "rhel4edge") + + # We are notified that we can also start the system one + b.wait_in_text("#overview div.pf-v5-c-alert .pf-v5-c-alert__title", "Docker service is available") + b.click("#overview div.pf-v5-c-alert .pf-v5-c-alert__action > button:contains(Start)") + b.wait_not_present("#overview div.pf-v5-c-alert .pf-v5-c-alert__title") + + checkImage(b, IMG_REGISTRY, "system") + checkImage(b, IMG_REGISTRY, "admin") + b.wait_visible("#containers-containers .pod-name:contains('pod_user')") + b.wait_visible("#containers-containers .pod-name:contains('pod_system')") + b.wait_visible("#containers-containers .container-name:contains('a')") + b.wait_visible("#containers-containers .container-name:contains('b')") + + # Owner select should appear + b.wait_visible("#containers-containers-owner") + + # Also user selection in image download should be visible + b.click("#image-actions-dropdown") + b.click("button:contains(Download new image)") + b.wait_visible('div.pf-v5-c-modal-box header:contains("Search for an image")') + b.wait_visible("div.pf-v5-c-modal-box footer button:contains(Download):disabled") + b.wait_visible("#as-user") + b.click(".pf-v5-c-modal-box button:contains('Cancel')") + b.wait_not_present('div.pf-v5-c-modal-box header:contains("Search for an image")') + + # Check that when we filter only system stuff an then drop privileges that we show user stuff + b.set_val("#containers-containers-owner", "system") + b.wait_not_present("#containers-containers .pod-name:contains('pod_user')") + b.wait_not_present("#containers-containers .container-name:contains('b')") + # Checking images is harder but if there would be more than one this would fail + b.wait_visible(f"#containers-images:contains('{IMG_REGISTRY}')") + + b.drop_superuser() + b.wait_visible("#containers-containers .pod-name:contains('pod_user')") + b.wait_visible("#containers-containers .container-name:contains('b')") + # Checking images is harder but if there would be more than one this would fail + b.wait_visible(f"#containers-images:contains('{IMG_REGISTRY}')") + + # Check showing of entrypoint + b.click("#containers-containers-create-container-btn") + b.click("#create-image-image-select-typeahead") + b.click(f'button.pf-v5-c-select__menu-item:contains("{IMG_REGISTRY}")') + b.wait_val("#run-image-dialog-command", '/etc/docker/registry/config.yml') + b.wait_text("#run-image-dialog-entrypoint", '/entrypoint.sh') + + # Deleting image will cleanup both command and entrypoint + b.click("button.pf-v5-c-select__toggle-clear") + b.wait_val("#run-image-dialog-command", '') + b.wait_not_present("#run-image-dialog-entrypoint") + + # Edited command will not be cleared + b.click("#create-image-image-select-typeahead") + b.click(f'button.pf-v5-c-select__menu-item:contains("{IMG_REGISTRY}")') + b.wait_val("#run-image-dialog-command", '/etc/docker/registry/config.yml') + b.set_input_text("#run-image-dialog-command", '/etc/docker/registry/config.yaml') + b.click("button.pf-v5-c-select__toggle-clear") + b.wait_not_present("#run-image-dialog-entrypoint") + b.wait_val("#run-image-dialog-command", '/etc/docker/registry/config.yaml') + + # Setting a new image will still keep the old command and not prefill it + b.click("#create-image-image-select-typeahead") + b.click(f'button.pf-v5-c-select__menu-item:contains({IMG_ALPINE})') + b.wait_visible("#run-image-dialog-pull-latest-image") + b.wait_val("#run-image-dialog-command", '/etc/docker/registry/config.yaml') + + b.logout() + + if self.machine.ostree_image: + self.machine.execute("echo foobar | passwd --stdin root") + self.write_file("/etc/ssh/sshd_config.d/99-root-password.conf", "PermitRootLogin yes", + post_restore_action="systemctl try-restart sshd") + self.machine.execute("systemctl try-restart sshd") + + # Test that when root is logged in we don't present "user" and "system" + self.login_and_go("/docker", user="root", enable_root_login=True) + b.wait_visible("#app") + + # `User Service is also available` banner should not be present + b.wait_not_present("#overview div.pf-v5-c-alert") + # There should not be any duplicate images listed + # The "busybox" and "alpine" images have been deleted by _testBasic. + showImages(b) + self.waitNumImages(self.system_images_count - 2) + # There should not be 'owner' selector + b.wait_not_present("#containers-containers-owner") + + # Test the isSystem boolean for searching + # https://github.com/cockpit-project/cockpit-podman/pull/891 + b.click("#containers-containers-create-container-btn") + b.set_input_text("#create-image-image-select-typeahead", "registry") + b.wait_visible('button.pf-v5-c-select__menu-item:contains("registry")') + + def testBasicUser(self): + self._testBasic(False) + + def _testBasic(self, auth): + b = self.browser + + def clickDeleteImage(image_sel): + b.click(f'{image_sel} .pf-v5-c-menu-toggle') + b.click(image_sel + " button.btn-delete") + + if not auth: + self.allow_browser_errors("Failed to start system docker.socket.*") + + expected_ws = "" + if auth and self.machine.ostree_image: + expected_ws += "ws" + + self.login(auth) + + # Check all containers + if auth: + checkImage(b, IMG_ALPINE, "system") + checkImage(b, IMG_BUSYBOX, "system") + checkImage(b, IMG_REGISTRY, "system") + + checkImage(b, IMG_ALPINE, "admin") + checkImage(b, IMG_BUSYBOX, "admin") + checkImage(b, IMG_REGISTRY, "admin") + + # Check order of images + text = b.text("#containers-images table") + if auth: + # all user images before all system images + self.assertRegex(text, ".*admin.*system.*") + self.assertNotRegex(text, ".*system.*admin.*") + else: + self.assertNotIn("system", text) + # images are sorted alphabetically + self.assertRegex(text, ".*/test-alpine.*/test-busybox.*/test-registry") + + # build a dummy image so that the timestamp is "today" (for predictable pixel tests) + # ensure that CMD neither comes first (docker rmi leaves that layer otherwise) + # nor last (then the topmost layer does not match the image ID) + IMG_HELLO_LATEST = "localhost/test-hello:latest" + self.machine.execute(f"""set -eu; D={self.vm_tmpdir}/hello; + mkdir $D + printf 'FROM scratch\\nCOPY test.txt /\\nCMD ["/run.sh"]\\nCOPY test.txt /test2.txt\\n' > $D/Containerfile + echo hello > $D/test.txt""") + self.execute(auth, f"docker build -t {IMG_HELLO_LATEST} {self.vm_tmpdir}/hello") + + # prepare image ids - much easier to pick a specific container + images = {} + for image in self.execute(auth, "docker images --noheading --no-trunc").strip().split("\n"): + # sha256: + items = image.split() + images[f"{items[0]}:{items[1]}"] = items[2].split(":")[-1] + + # show image listing toggle + hello_sel = f"#containers-images tbody tr[data-row-id=\"{images[IMG_HELLO_LATEST]}{auth}\"]".lower() + b.wait_visible(hello_sel) + b.click(hello_sel + " td.pf-v5-c-table__toggle button") + b.click(hello_sel + " .pf-v5-c-menu-toggle") + b.wait_visible(hello_sel + " button.btn-delete") + b.wait_in_text("#containers-images tbody.pf-m-expanded tr .image-details:first-child", "Command/run.sh") + # Show history + b.click("#containers-images tbody.pf-m-expanded .pf-v5-c-tabs__list li:nth-child(2) button") + first_row_sel = "#containers-images .pf-v5-c-table__expandable-row.pf-m-expanded tbody:first-of-type" + b.wait_in_text(f"{first_row_sel} td[data-label=\"ID\"]", + images[IMG_HELLO_LATEST][:12]) + created_sel = f"{first_row_sel} td[data-label=\"Created\"]" + b.wait_in_text(f"{created_sel}", "today at") + # topmost (last) layer + created_sel = f"{first_row_sel} td[data-label=\"Created by\"]" + b.wait_in_text(f"{created_sel}", "COPY") + b.wait_in_text(f"{created_sel}", "in /test2.txt") + # initial (first) layer + last_row_sel = "#containers-images .pf-v5-c-table__expandable-row.pf-m-expanded tbody:last-of-type" + b.wait_in_text(f"{last_row_sel} td[data-label=\"Created by\"]", "COPY") + + self.execute(auth, f"docker rmi {IMG_HELLO_LATEST}") + b.wait_not_present(hello_sel) + + # make sure no running containers shown; on CoreOS there's the cockpit/ws container + self.filter_containers('running') + if auth and self.machine.ostree_image: + self.waitContainerRow("ws") + else: + b.wait_in_text("#containers-containers", "No running containers") + + if auth: + # Run two containers as system (first exits immediately) + self.execute(auth, f"docker run -d --name test-sh-system --stop-timeout 0 {IMG_ALPINE} sh") + self.execute(auth, f"docker run -d --name swamped-crate-system --stop-timeout 0 {IMG_BUSYBOX} sleep 1000") + + # Test owner filtering + if auth: + self.waitNumImages(self.user_images_count + self.system_images_count) + self.waitNumContainers(2, True) + + def verify_system(): + self.waitNumImages(self.system_images_count) + b.wait_in_text("#containers-images", "system") + self.waitNumContainers(1, True) + b.wait_in_text("#containers-containers", "system") + + b.set_val("#containers-containers-owner", "system") + verify_system() + b.set_val("#containers-containers-owner", "all") + b.go("#/?owner=system") + verify_system() + + def verify_user(): + self.waitNumImages(self.user_images_count) + b.wait_in_text("#containers-images", "admin") + self.waitNumContainers(1, False) + b.wait_in_text("#containers-containers", "admin") + + b.set_val("#containers-containers-owner", "user") + verify_user() + b.set_val("#containers-containers-owner", "all") + b.go("#/?owner=user") + verify_user() + + b.set_val("#containers-containers-owner", "all") + self.waitNumImages(self.user_images_count + self.system_images_count) + self.waitNumContainers(2, True) + else: # No 'owner' selector when not privileged + b.wait_not_present("#containers-containers-owner") + + system_containers = {} + for container in self.execute(True, "docker ps --all --no-trunc").strip().split("\n")[1:]: + # + items = container.split() + system_containers[items[-1]] = items[0] + # running busybox shown + if auth: + self.waitContainerRow("swamped-crate-system") + self.waitContainer(system_containers["swamped-crate-system"], True, name='swamped-crate-system', + image=IMG_BUSYBOX, cmd="sleep 1000", state='Running') + + # exited alpine not shown + b.wait_not_in_text("#containers-containers", "alpine") + + # show all containers and check status + b.go("#/?container=all") + + # exited alpine under everything list + b.wait_visible("#containers-containers") + if auth: + self.waitContainer(system_containers["test-sh-system"], True, name='test-sh-system', image=IMG_ALPINE, + cmd='sh', state=NOT_RUNNING) + + if auth: + self.performContainerAction("swamped-crate-system", "Delete") + self.confirm_modal("Cancel") + + # Checked order of containers + expected = ["swamped-crate-user"] + if auth: + expected.extend(["swamped-crate-system", "test-sh-system"]) + expected.extend([expected_ws]) + b.wait_collected_text("#containers-containers .container-name", ''.join(sorted(expected))) + + # show running container + self.filter_containers('running') + if auth: + self.waitContainer(system_containers["swamped-crate-system"], True, name='swamped-crate-system', + image=IMG_BUSYBOX, cmd="sleep 1000", state='Running') + # check exited alpine not in running list + b.wait_not_in_text("#containers-containers", "alpine") + + # delete running container busybox using force delete + if auth: + self.performContainerAction("swamped-crate-system", "Delete") + self.confirm_modal("Force delete") + self.waitContainerRow("swamped-crate-system", False) + + self.filter_containers("all") + + if auth: + self.waitContainerRow("test-sh-system") + self.performContainerAction("test-sh-system", "Delete") + self.confirm_modal("Delete") + b.wait_not_in_text("#containers-containers", "test-sh-system") + + # delete image busybox that hasn't been used + # First try to just untag and then remove with more tags + self.execute(auth, f"docker tag {IMG_BUSYBOX} {IMG_BUSYBOX}:1") + self.execute(auth, f"docker tag {IMG_BUSYBOX} {IMG_BUSYBOX}:2") + self.execute(auth, f"docker tag {IMG_BUSYBOX} {IMG_BUSYBOX}:3") + self.execute(auth, f"docker tag {IMG_BUSYBOX} {IMG_BUSYBOX}:4") + + busybox_sel = f"#containers-images tbody tr[data-row-id=\"{images[IMG_BUSYBOX_LATEST]}{auth}\"]".lower() + b.click(busybox_sel + " td.pf-v5-c-table__toggle button") + + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:1") + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:2") + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:3") + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:4") + + clickDeleteImage(busybox_sel) + self.assertTrue(b.get_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX_LATEST}']")) + b.set_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX}:1']", True) + b.set_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX}:3']", True) + b.set_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX_LATEST}']", False) + self.confirm_modal("Delete") + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX_LATEST}") + b.wait_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:2") + b.wait_not_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:1") + b.wait_not_in_text(busybox_sel + " + tr", f"{IMG_BUSYBOX}:3") + + clickDeleteImage(busybox_sel) + b.click("#delete-all") + self.assertTrue(b.get_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX_LATEST}']")) + self.assertTrue(b.get_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX}:2']")) + self.assertTrue(b.get_checked(f".pf-v5-c-check__input[aria-label='{IMG_BUSYBOX}:4']")) + self.confirm_modal("Delete") + self.confirm_modal("Force delete") + b.wait_not_present(busybox_sel) + + # Check that we correctly show networking information + # Rootless don't have this info + if auth: + self.execute(auth, f"docker run -dt --name net_check --stop-timeout 0 {IMG_ALPINE}") + self.toggleExpandedContainer("net_check") + b.wait_in_text(".pf-m-expanded .container-details-networking", + self.execute(auth, """ + docker inspect --format '{{.NetworkSettings.Gateway}}' net_check""").strip()) + b.wait_in_text(".pf-m-expanded .container-details-networking", + self.execute(auth, """ + docker inspect --format '{{.NetworkSettings.IPAddress}}' net_check""").strip()) + b.wait_in_text(".pf-m-expanded .container-details-networking", + self.execute(auth, """ + docker inspect --format '{{.NetworkSettings.MacAddress}}' net_check""").strip()) + self.execute(auth, "docker stop net_check") + b.wait(lambda: self.execute(True, "docker ps --all | grep -e net_check -e Exited")) + self.toggleExpandedContainer("net_check") + sha = self.execute(auth, "docker inspect --format '{{.Id}}' net_check").strip() + self.waitContainer(sha, auth, state='Exited') + + # delete image alpine that has been used by a container + self.execute(auth, f"docker run -d --name test-sh4 --stop-timeout 0 {IMG_ALPINE} sh") + # our pixel test expects both containers to be in state "Exited" + sha = self.execute(auth, "docker inspect --format '{{.Id}}' test-sh4").strip() + self.waitContainer(sha, auth, name="test-sh4", state='Exited') + if auth: + b.assert_pixels('#app', "overview", ignore=[".ignore-pixels"], skip_layouts=["rtl", "mobile"]) + alpine_sel = f"#containers-images tbody tr[data-row-id=\"{images[IMG_ALPINE_LATEST]}{auth}\"]".lower() + b.wait_visible(alpine_sel) + b.click(alpine_sel + " td.pf-v5-c-table__toggle button") + clickDeleteImage(alpine_sel) + self.confirm_modal("Delete") + self.confirm_modal("Force delete") + b.wait_not_present(alpine_sel) + + b.wait_collected_text("#containers-containers .container-name", expected_ws) + self.execute(auth, f"docker run -d --name c --stop-timeout 0 {IMG_REGISTRY} sh") + b.wait_collected_text("#containers-containers .container-name", "c" + expected_ws) + self.execute(auth, f"docker run -d --name a --stop-timeout 0 {IMG_REGISTRY} sh") + b.wait_collected_text("#containers-containers .container-name", "ac" + expected_ws) + + self.execute(False, f"docker run -d --name b --stop-timeout 0 {IMG_REGISTRY} sh") + if auth: + b.wait_collected_text("#containers-containers .container-name", "abc" + expected_ws) + self.execute(False, f"docker run -d --name doremi --stop-timeout 0 {IMG_REGISTRY} sh") + b.wait_collected_text("#containers-containers .container-name", "abcdoremi" + expected_ws) + b.wait(lambda: self.getContainerAttr("doremi", "State") in NOT_RUNNING) + else: + b.wait_collected_text("#containers-containers .container-name", "abc") + + # Test intermediate images + b.wait_not_present(".listing-action") + tmpdir = self.execute(auth, "mktemp -d").strip() + self.execute(auth, f"echo 'FROM {IMG_REGISTRY}\nRUN ls' > {tmpdir}/Dockerfile") + self.execute(auth, f"docker build {tmpdir}") + + b.wait_not_in_text("#containers-images", ":") + b.click(".listing-action button:contains('Show intermediate images')") + b.wait_in_text("#containers-images", ":") + b.wait_in_text("#containers-images tbody:last-child td[data-label=Created]", "today at") + + b.click(".listing-action button:contains('Hide intermediate images')") + b.wait_not_in_text("#containers-images", ":") + + # Intermediate images are not shown in create container dialog + b.click("#containers-containers-create-container-btn") + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + b.click("#create-image-image-select-typeahead") + b.wait_visible(f".pf-v5-c-select__menu-item:contains('{IMG_REGISTRY}')") + b.wait_not_present(".pf-v5-c-select__menu-item:contains('none')") + b.click(".pf-v5-c-modal-box .btn-cancel") + b.wait_not_present(".pf-v5-c-modal-box") + + # Delete intermediate images + intermediate_image_sel = "#containers-images tbody:last-child:contains(':')" + b.click(".listing-action button:contains('Show intermediate images')") + clickDeleteImage(intermediate_image_sel) + self.confirm_modal("Delete") + b.wait_not_present(intermediate_image_sel) + + # Create intermediate image and use it in a container + tmpdir = self.execute(auth, "mktemp -d").strip() + self.execute(auth, f"echo 'FROM {IMG_REGISTRY}\nRUN ls' > {tmpdir}/Dockerfile") + IMG_INTERMEDIATE = 'localhost/test-intermediate' + self.execute(auth, f"docker build -t {IMG_INTERMEDIATE} {tmpdir}") + b.click(f'#containers-images tbody tr:contains("{IMG_INTERMEDIATE}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + b.click("#create-image-create-btn") + b.wait_not_present("div.pf-v5-c-modal-box") + self.waitContainerRow(IMG_INTERMEDIATE) + + # Integration tab should not crash with an intermediate image + self.toggleExpandedContainer(IMG_INTERMEDIATE) + b.click(".pf-m-expanded button:contains('Integration')") + + # Delete intermediate image which is in use + self.execute(auth, f"docker untag {IMG_INTERMEDIATE}") + clickDeleteImage(intermediate_image_sel) + self.confirm_modal("Delete") + self.confirm_modal("Force delete") + b.wait_not_in_text("#containers-images", ":") + b.wait_not_in_text("#containers-containers", IMG_INTERMEDIATE) + + def testCommitUser(self): + self._testCommit(False) + + def testCommitSystem(self): + self._testCommit(True) + + def _testCommit(self, auth): + b = self.browser + self.allow_browser_errors("Failed to commit container .* repository name must be lowercase") + + self.login(auth) + + # run a container (will exit immediately) and test the display of commit modal + self.execute(auth, f"docker run -d --name test-sh0 --stop-timeout 0 {IMG_ALPINE} sh -c 'ls -a'") + + self.filter_containers("all") + self.waitContainerRow("test-sh0") + self.toggleExpandedContainer("test-sh0") + + self.performContainerAction("test-sh0", "Commit") + b.wait_visible(".pf-v5-c-modal-box") + + b.wait_in_text(".pf-v5-c-modal-box__description", "state of the test-sh0 container") + + # Empty name yields warning + b.click("button:contains(Commit)") + b.wait_text("#commit-dialog-image-name-helper", "Image name is required") + b.wait_visible("button:contains(Commit):disabled") + b.wait_visible("button:contains('Force commit')") + # Warning should be cleaned when updating name + b.set_input_text("#commit-dialog-image-name", "foobar") + b.wait_not_present("button:contains('Force commit')") + b.wait_not_present("#commit-dialog-image-name-helper") + + # Existing name yields warning + b.set_input_text("#commit-dialog-image-name", IMG_ALPINE) + b.click("button:contains(Commit)") + b.wait_text("#commit-dialog-image-name-helper", "Image name is not unique") + b.wait_visible("button:contains(Commit):disabled") + b.wait_visible("button:contains('Force commit')") + # Warning should be cleaned when updating tag + b.set_input_text("#commit-dialog-image-tag", "foobar") + b.wait_not_present("button:contains('Force commit')") + b.wait_not_present("#commit-dialog-image-name-helper") + + # Check failing commit + b.set_input_text("#commit-dialog-image-name", "TEST") + b.click("button:contains(Commit)") + b.wait_in_text(".pf-v5-c-alert", "Failed to commit container test-sh0") + b.wait_in_text(".pf-v5-c-alert", "repository name must be lowercase") + + # Test cancel + self.confirm_modal("Cancel") + + # Force commit empty container + self.performContainerAction("test-sh0", "Commit") + b.wait_visible(".pf-v5-c-modal-box") + # We prefill command + b.wait_val("#commit-dialog-command", 'sh -c "ls -a"') + # Test docker format + b.set_checked("#commit-dialog-docker", True) + b.click("button:contains(Commit)") + self.confirm_modal("Force commit") + + # don't use waitNumImages() here, as we want to include anonymous images + def waitImageCount(expected): + if auth: + expected += self.system_images_count + + b.wait_in_text("#containers-images", f"{expected} images") + + waitImageCount(self.user_images_count + 1) + image_id = self.execute(auth, "docker images --sort created --format '{{.Id}}' | head -n 1").strip() + manifest_type = self.execute(auth, "docker inspect --format '{{.ManifestType}}' " + image_id).strip() + cmd = self.execute(auth, "docker inspect --format '{{.Config.Cmd}}' " + image_id).strip() + self.assertIn("docker.distribution.manifest", manifest_type) + self.assertEqual("[sh -c ls -a]", cmd) + + # Commit with name, tag, author and edited command + self.performContainerAction("test-sh0", "Commit") + b.wait_visible(".pf-v5-c-modal-box") + b.set_input_text("#commit-dialog-image-name", "newname") + b.set_input_text("#commit-dialog-image-tag", "24") + b.set_input_text("#commit-dialog-author", "MM") + b.set_input_text("#commit-dialog-command", "sh -c 'ps'") + + if auth: + b.assert_pixels(".pf-v5-c-modal-box", "commit", skip_layouts=["rtl"]) + + self.confirm_modal("Commit") + + waitImageCount(self.user_images_count + 2) + self.assertEqual(self.execute(auth, "docker inspect --format '{{.Author}}' newname:24").strip(), "MM") + self.assertEqual(self.execute(auth, "docker inspect --format '{{.Config.Cmd}}' newname:24").strip(), + "[sh -c ps]") + self.assertIn("vnd.oci.image.manifest", + self.execute(auth, "docker inspect --format '{{.ManifestType}}' newname:24").strip()) + + # Test commit of running container + self.execute(auth, f"docker run -d --name test-sh2 --stop-timeout 0 {IMG_BUSYBOX} sleep 1000") + self.performContainerAction("test-sh2", "Commit") + b.wait_visible(".pf-v5-c-modal-box") + b.set_input_text("#commit-dialog-image-name", "newname") + self.confirm_modal("Commit") + waitImageCount(self.user_images_count + 3) + self.assertEqual(self.execute(auth, + "docker inspect --format '{{.Config.Cmd}}' newname:latest").strip(), + "[sleep 1000]") + + # Test commit of running container with pause (also conflicting name through :latest) + # This only works on rootless with cgroupsv2 + if auth or self.has_cgroupsV2: + self.performContainerAction("test-sh2", "Commit") + b.wait_visible(".pf-v5-c-modal-box") + b.set_input_text("#commit-dialog-image-name", "newname") + b.set_checked("#commit-dialog-pause", True) + b.click("button:contains(Commit)") + self.confirm_modal("Force commit") + waitImageCount(self.user_images_count + 4) + + def testDownloadImage(self): + b = self.browser + execute = self.execute + + def prepare(): + # Create and start registry containers + self.execute(True, f"docker run -d -p 5000:5000 --name registry --stop-timeout 0 {IMG_REGISTRY}") + self.execute(True, f"docker run -d -p 6000:5000 --name registry_alt --stop-timeout 0 {IMG_REGISTRY}") + # Add local insecure registry into registries conf + self.machine.write("/etc/containers/registries.conf", REGISTRIES_CONF) + self.execute(True, "systemctl stop docker.service") + # Push busybox image to the local registries + self.execute(True, + f"docker tag {IMG_BUSYBOX} localhost:5000/my-busybox; docker push localhost:5000/my-busybox") + self.execute(True, + f"docker tag {IMG_BUSYBOX} localhost:6000/my-busybox; docker push localhost:6000/my-busybox") + # Untag busybox image which duplicates the image we are about to download + self.execute(True, f"docker rmi -f {IMG_BUSYBOX} localhost:5000/my-busybox localhost:6000/my-busybox") + self.execute(False, f"docker rmi -f {IMG_BUSYBOX}") + + class DownloadImageDialog(): + def __init__(self, test_obj, imageName, imageTag=None, user="system"): + self.imageName = imageName + self.imageTag = imageTag + self.user = user + self.imageSha = "" + self.assertTrue = test_obj.assertTrue + + def openDialog(self): + # Open get new image modal + b.click("#image-actions-dropdown") + b.click("button:contains(Download new image)") + b.wait_visible('div.pf-v5-c-modal-box header:contains("Search for an image")') + b.wait_visible("div.pf-v5-c-modal-box footer button:contains(Download):disabled") + + return self + + def fillDialog(self): + # Search for image specified with self.imageName and self.imageTag + b.click(f"#{self.user}") + b.set_val('#registry-select', "localhost:5000") + # HACK: Sometimes the value is not shown fully. FIXME + b.set_input_text("#search-image-dialog-name", self.imageName, value_check=False) + if self.imageTag: + b.set_input_text(".image-tag-entry input", self.imageTag) + + return self + + def selectImageAndDownload(self): + # Select and download the self.imageName image + b.click(f".pf-v5-c-data-list .image-name:contains({self.imageName})") + b.click("div.pf-v5-c-modal-box footer button:contains(Download)") + b.wait_not_present("div.pf-v5-c-modal-box") + + return self + + def expectDownloadErrorForNonExistingTag(self): + title = f"Danger alert:Failed to download image localhost:5000/{self.imageName}:{self.imageTag}" + b.wait_visible(f'h4.pf-v5-c-alert__title:contains("{title}")') + + return self + + def expectSearchErrorForNotExistingImage(self): + b.wait_visible(f".pf-v5-c-modal-box__body:contains(No results for {self.imageName})") + b.click(".pf-v5-c-modal-box button.btn-cancel") + b.wait_not_present(".pf-v5-c-modal-box__body") + + return self + + def expectDownloadSuccess(self): + # Confirm that the modal dialog is not open anymore + b.wait_not_present('div.pf-v5-c-modal-box') + # Confirm that the image got downloaded + checkImage(b, + f"localhost:5000/{self.imageName}:{self.imageTag or 'latest'}", + "system" if self.user == "system" else "admin") + + # Confirm that no error has happened + b.wait_not_present('h4.pf-v5-c-alert__title:contains("Failed to download image")') + + # Find out this image ID + container_name = f"localhost:5000/{self.imageName}:{self.imageTag or 'latest'}" + self.imageSha = execute(self.user == "system", + f"docker inspect --format '{{{{.Id}}}}' {container_name}").strip() + + return self + + def deleteImage(self, force=False, another=None): + imageTagSuffix = ":" + (self.imageTag or 'latest') + + # Select the image row + + # show image listing toggle + imageId = f"{self.imageSha}{'true' if self.user == 'system' else 'false'}" + sel = f"#containers-images tbody tr[data-row-id=\"{imageId}\"]" + b.wait_visible(sel) + b.click(sel + " td.pf-v5-c-table__toggle button") + + # Click the delete icon on the image row + b.click(sel + " .pf-v5-c-menu-toggle") + b.click(sel + ' button.btn-delete') + + if another: + b.click("#delete-all") + sel = f".pf-v5-c-check__input[aria-label='localhost:5000/{self.imageName}{imageTagSuffix}']" + self.assertTrue(b.get_checked(sel)) + self.assertTrue(b.get_checked(f".pf-v5-c-check__input[aria-label='{another}']")) + b.click("#delete-all") + b.wait_visible("#btn-img-delete:disabled") + + b.set_checked( + f".pf-v5-c-check__input[aria-label='localhost:5000/{self.imageName}{imageTagSuffix}']", True) + b.set_checked(f".pf-v5-c-check__input[aria-label='{another}']", True) + + # Confirm deletion in the delete dialog + b.click(".pf-v5-c-modal-box #btn-img-delete") + + if force: + # Confirm force delete + b.click(".pf-v5-c-modal-box button:contains('Force delete')") + + b.wait_not_present(sel) + + return self + + prepare() + + self.login() + + # Test registries + b.click("#image-actions-dropdown") + b.click("button:contains(Download new image)") + b.wait_visible('div.pf-v5-c-modal-box header:contains("Search for an image")') + # HACK: Sometimes the value is not shown fully. FIXME + b.set_input_text("#search-image-dialog-name", "my-busybox", value_check=False) + + b.wait_visible(".pf-v5-c-data-list .image-name:contains('localhost:5000/my-busybox')") + b.wait_visible(".pf-v5-c-data-list .image-name:contains('localhost:6000/my-busybox')") + b.assert_pixels(".docker-search", "download", skip_layouts=["rtl"]) + + b.set_val('#registry-select', "localhost:6000") + b.wait_not_present(".pf-v5-c-data-list .image-name:contains('localhost:5000/my-busybox')") + b.wait_visible(".pf-v5-c-data-list .image-name:contains('localhost:6000/my-busybox')") + b.click(".pf-v5-c-modal-box button:contains('Cancel')") + b.wait_not_present('div.pf-v5-c-modal-box') + + dialog0 = DownloadImageDialog(self, imageName='my-busybox', user="system") + dialog0.openDialog() \ + .fillDialog() \ + .selectImageAndDownload() \ + .expectDownloadSuccess() + dialog0.deleteImage() + + dialog1 = DownloadImageDialog(self, imageName='my-busybox', user="user") + dialog1.openDialog() \ + .fillDialog() \ + .selectImageAndDownload() \ + .expectDownloadSuccess() + # test recognition/deletion of multiple image tags + second_tag = "localhost/copybox:latest" + self.execute(False, f"docker tag localhost:5000/my-busybox {second_tag}") + # expand details + b.click("#containers-images tr:contains('my-busybox') td.pf-v5-c-table__toggle button") + b.wait_in_text("#containers-images tbody.pf-m-expanded tr .image-details", second_tag) + dialog1.deleteImage(True, another=second_tag) + + dialog = DownloadImageDialog(self, imageName='my-busybox', imageTag='latest', user="system") + dialog.openDialog() \ + .fillDialog() \ + .selectImageAndDownload() \ + .expectDownloadSuccess() \ + .deleteImage() + + dialog = DownloadImageDialog(self, imageName='foobar') + dialog.openDialog() \ + .fillDialog() \ + .expectSearchErrorForNotExistingImage() + + dialog = DownloadImageDialog(self, imageName='my-busybox', imageTag='foobar') + dialog.openDialog() \ + .fillDialog() \ + .selectImageAndDownload() \ + .expectDownloadErrorForNonExistingTag() + + def testLifecycleOperationsUser(self): + self._testLifecycleOperations(False) + + def testLifecycleOperationsSystem(self): + self._testLifecycleOperations(True) + + def _testLifecycleOperations(self, auth): + b = self.browser + + if not auth: + self.allow_browser_errors("Failed to start system docker.socket.*") + + self.login() + self.filter_containers('all') + + # run a container + self.execute(auth, f""" + docker run -d --name swamped-crate --stop-timeout 0 {IMG_BUSYBOX} sh -c 'echo 123; sleep infinity'; + docker stop swamped-crate""") + b.wait(lambda: self.execute(auth, "docker ps --all | grep -e swamped-crate -e Exited")) + + b.wait_visible("#containers-containers") + container_sha = self.execute(auth, "docker inspect --format '{{.Id}}' swamped-crate").strip() + self.waitContainer(container_sha, auth, name='swamped-crate', image=IMG_BUSYBOX, + state='Exited', owner="system" if auth else "admin") + b.click("#containers-containers tbody tr:contains('swamped-crate') .pf-v5-c-menu-toggle") + + if not auth: + # Checkpoint/restore is not supported on user containers yet - the related buttons should not be shown + # Check that the restore option is not present + b.wait_not_present(self.getContainerAction('swamped-crate', 'Restore')) + + # Health check is not set up + b.wait_not_present(self.getContainerAction('swamped-crate', 'Run health check')) + + b.click("#containers-containers tbody tr:contains('swamped-crate') .pf-v5-c-menu-toggle") + + # Start the container + self.performContainerAction(IMG_BUSYBOX, "Start") + + self.waitContainer(container_sha, auth, name='swamped-crate', image=IMG_BUSYBOX, + state='Running', owner="system" if auth else "admin") + + def get_cpu_usage(sel): + cpu = self.getContainerAttr(sel, "CPU") + self.assertIn('%', cpu) + # If it not a number it will raise ValueError which is what we want to know + return float(cpu[:-1]) + + # Check we show usage + b.wait(lambda: self.getContainerAttr(IMG_BUSYBOX, "CPU") != "") + b.wait(lambda: self.getContainerAttr(IMG_BUSYBOX, "Memory") != "") + memory = self.getContainerAttr(IMG_BUSYBOX, "Memory") + if auth or self.has_cgroupsV2: + cpu = get_cpu_usage(IMG_BUSYBOX) + + self.assertIn('/', memory) + numbers = memory.split('/') + self.assertTrue(numbers[0].strip().replace('.', '', 1).isdigit()) + full = numbers[1].strip().split() + self.assertTrue(full[0].replace('.', '', 1).isdigit()) + self.assertIn(full[1], ["GB", "MB"]) + + # Test that the value is updated dynamically + self.execute(auth, "docker exec -i swamped-crate sh -c 'dd bs=1024 < /dev/urandom > /dev/null &'") + b.wait(lambda: get_cpu_usage(IMG_BUSYBOX) > cpu) + self.execute(auth, "docker exec swamped-crate sh -c 'pkill dd'") + else: + # No support for CGroupsV2 + self.assertEqual(self.getContainerAttr(IMG_BUSYBOX, "CPU"), "n/a") + self.assertEqual(memory, "n/a") + + # Restart the container; there is no steady state change in the visible UI, so look for + # a changed data-started-at attribute + old_start = self.getStartTime("swamped-crate", auth=auth) + b.wait_in_text(f'#containers-containers tr[data-started-at="{old_start}"]', "swamped-crate") + self.performContainerAction(IMG_BUSYBOX, "Force restart") + new_start = self.waitRestart("swamped-crate", old_start, auth=auth) + b.wait_in_text(f'#containers-containers tr[data-started-at="{new_start}"]', "swamped-crate") + self.waitContainer(container_sha, auth, name='swamped-crate', image=IMG_BUSYBOX, state='Running') + + self.waitContainerRow(IMG_BUSYBOX) + if not auth: + # Check that the checkpoint option is not present for rootless + b.click(f"#containers-containers tbody tr:contains('{IMG_BUSYBOX}') .pf-v5-c-menu-toggle") + b.wait_visible(self.getContainerAction(IMG_BUSYBOX, 'Force stop')) + b.wait_not_present(self.getContainerAction(IMG_BUSYBOX, 'Checkpoint')) + b.click(f"#containers-containers tbody tr:contains('{IMG_BUSYBOX}') .pf-v5-c-menu-toggle") + # Stop the container + self.performContainerAction(IMG_BUSYBOX, "Force stop") + + self.waitContainer(container_sha, auth, name='swamped-crate', image=IMG_BUSYBOX) + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in NOT_RUNNING) + b.wait(lambda: self.getContainerAttr("swamped-crate", "CPU") == "") + b.wait(lambda: self.getContainerAttr("swamped-crate", "Memory") == "") + + # Check that container details are not lost when the container is stopped + self.toggleExpandedContainer("swamped-crate") + b.click(".pf-m-expanded button:contains('Integration')") + b.wait_visible(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Environment variables")') + + # Check that console reconnects when container starts + b.click(".pf-m-expanded button:contains('Console')") + b.wait_text(".pf-m-expanded .pf-v5-c-empty-state", "Container is not running") + self.performContainerAction("swamped-crate", "Start") + b.wait_in_text(".pf-m-expanded .xterm-accessibility-tree", "/ # ") + b.focus(".pf-m-expanded .xterm-helper-textarea") + b.key_press('clear\r') + b.wait_not_in_text(".pf-m-expanded .xterm-accessibility-tree", "clear") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(1)", "/ # ") + b.key_press('echo hello\r') + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(2)", "hello") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(3)", "/ # ") + self.performContainerAction("swamped-crate", "Stop") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(3)", "/ # disconnected ") + sha = self.execute(auth, "docker inspect --format '{{.Id}}' swamped-crate").strip() + self.waitContainer(sha, auth, name='swamped-crate', image=IMG_BUSYBOX, state=NOT_RUNNING) + self.performContainerAction("swamped-crate", "Start") + self.waitContainer(sha, auth, state='Running') + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(1)", "/ # ") + b.wait_not_in_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(2)", "hello") + + # Check that logs reconnect when container starts + b.click(".pf-m-expanded button:contains('Logs')") + self.performContainerAction("swamped-crate", "Stop") + self.waitContainer(sha, auth, state=NOT_RUNNING) + b.wait_in_text(".pf-m-expanded .container-logs .xterm-accessibility-tree", "Streaming disconnected") + self.performContainerAction("swamped-crate", "Start") + b.wait_in_text(".pf-m-expanded .container-logs .xterm-accessibility-tree", "Streaming disconnected123") + + def testCheckpointRestore(self): + m = self.machine + b = self.browser + + self.login() + self.filter_containers('all') + + if not self.has_criu: + # On cgroupsv1 systems just check that we get expected error messages + + # Run a container + self.execute(True, f"docker run -dit --name swamped-crate --stop-timeout 0 {IMG_BUSYBOX} sh") + b.wait(lambda: self.execute(True, "docker ps --all | grep -e swamped-crate")) + + # Checkpoint the container + self.performContainerAction(IMG_BUSYBOX, "Checkpoint") + b.set_checked('.pf-v5-c-modal-box input#checkpoint-dialog-keep', True) + b.set_checked('.pf-v5-c-modal-box input#checkpoint-dialog-tcpEstablished', True) + b.click('.pf-v5-c-modal-box button:contains(Checkpoint)') + b.wait_not_present('.modal_dialog') + + def criu_alert(): + text = b.text(".pf-v5-c-alert.pf-m-danger > .pf-v5-c-alert__description").lower() + return "checkpoint/restore requires at least criu" in text or "failed to check for criu" in text + b.wait(criu_alert) + return + + # Run a container + mac_address = '92:d0:c6:0a:29:38' + self.execute(True, f""" + docker run -dit --mac-address {mac_address} --name swamped-crate --stop-timeout 0 {IMG_BUSYBOX} sh; + docker stop swamped-crate + """) + b.wait(lambda: self.execute(True, "docker ps --all | grep -e swamped-crate -e Exited")) + + # Check that the restore option is not present (i.e. start is a regular button) + b.click(f"#containers-containers tbody tr:contains('{IMG_BUSYBOX}') .pf-v5-c-menu-toggle") + b.wait_not_present(self.getContainerAction(IMG_BUSYBOX, 'Restore')) + b.click(f"#containers-containers tbody tr:contains('{IMG_BUSYBOX}') .pf-v5-c-menu-toggle") + + # Start the container + self.performContainerAction("swamped-crate", "Start") + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in 'Running') + + self.toggleExpandedContainer("swamped-crate") + b.wait_visible(".pf-m-expanded button:contains('Details')") + b.wait_not_present(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Latest checkpoint")') + + # Checkpoint the container + self.performContainerAction("swamped-crate", "Checkpoint") + b.set_checked('.pf-v5-c-modal-box input#checkpoint-dialog-keep', True) + b.set_checked('.pf-v5-c-modal-box input#checkpoint-dialog-tcpEstablished', True) + b.click('.pf-v5-c-modal-box button:contains(Checkpoint)') + + with b.wait_timeout(300): + b.wait_not_present(".pf-v5-c-modal-box") + + if self.has_criu: + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in NOT_RUNNING) + b.wait_in_text( + f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Latest checkpoint") + dd', + 'today at' + ) + else: + # expect proper error message + b.wait_in_text(".pf-v5-c-alert.pf-m-danger", "Failed to checkpoint container swamped-crate") + b.wait(lambda: "checkpoint/restore requires at least criu" in + b.text(".pf-v5-c-alert.pf-m-danger > .pf-v5-c-alert__description").lower()) + return + + # Restore the container + self.waitContainerRow("swamped-crate") + self.performContainerAction("swamped-crate", "Restore") + b.set_checked('.pf-v5-c-modal-box input#restore-dialog-keep', True) + b.set_checked('.pf-v5-c-modal-box input#restore-dialog-tcpEstablished', True) + b.set_checked('.pf-v5-c-modal-box input#restore-dialog-ignoreStaticIP', True) + b.set_checked('.pf-v5-c-modal-box input#restore-dialog-ignoreStaticMAC', True) + b.click('.pf-v5-c-modal-box button:contains(Restore)') + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in 'Running') + + # A new MAC address should have been generated + # Fixed in docker 4.4.0 https://github.com/containers/docker/issues/16666 + cmd = "docker inspect --format '{{.NetworkSettings.MacAddress}}' swamped-crate" + new_mac_address = self.execute(True, cmd).strip() + if docker_version(self) >= (4, 4, 0): + self.assertNotEqual(new_mac_address, mac_address) + else: + self.assertEqual(new_mac_address, mac_address) + + # Checkpoint the container without stopping + self.waitContainerRow("swamped-crate") + self.performContainerAction("swamped-crate", "Checkpoint") + b.set_checked('.pf-v5-c-modal-box input#checkpoint-dialog-leaveRunning', True) + b.click('.pf-v5-c-modal-box button:contains(Checkpoint)') + b.wait_not_present('.modal_dialog') + + # Stop the container + m.execute("docker stop swamped-crate") + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in NOT_RUNNING) + + # Restore the container + self.performContainerAction("swamped-crate", "Restore") + b.click('.pf-v5-c-modal-box button:contains(Restore)') + b.wait(lambda: self.getContainerAttr("swamped-crate", "State") in 'Running') + + def testNotRunning(self): + b = self.browser + + def disable_system(): + self.execute(True, "systemctl disable --now docker.socket; systemctl stop docker.service; systemctl stop containerd.service") + + def enable_system(): + self.execute(True, "systemctl enable --now docker.socket") + + def is_active_system(string): + b.wait(lambda: self.execute(True, "systemctl is-active docker.socket || true").strip() == string) + + def is_enabled_system(string): + b.wait(lambda: self.execute(True, "systemctl is-enabled docker.socket || true").strip() == string) + + disable_system() + self.login_and_go("/docker") + + # Troubleshoot action + b.click("#app .pf-v5-c-empty-state button.pf-m-link") + b.enter_page("/system/services") + # services page is too slow + with b.wait_timeout(60): + b.wait_in_text("#service-details", "docker.socket") + + # Start action, with enabling (by default) + b.go("/docker") + b.enter_page("/docker") + b.click("#app .pf-v5-c-empty-state button.pf-m-primary") + + b.wait_visible("#containers-containers") + b.wait_not_present("#overview div.pf-v5-c-alert.pf-m-info") + + is_active_system("active") + is_enabled_system("enabled") + + # Start action, without enabling + disable_system() + b.click("#app .pf-v5-c-empty-state input[type=checkbox]") + b.assert_pixels("#app .pf-v5-c-empty-state", "docker-service-disabled", skip_layouts=["medium", "mobile"]) + b.click("#app .pf-v5-c-empty-state button.pf-m-primary") + + b.wait_visible("#containers-containers") + is_enabled_system("disabled") + is_active_system("active") + + b.logout() + disable_system() + # HACK: Due to https://github.com/containers/docker/issues/7180, avoid + # user docker.service to time out; make sure to start it afresh + self.login_and_go("/docker") + self.login_and_go("/docker") + b.wait_in_text("#overview div.pf-v5-c-alert .pf-v5-c-alert__title", "Docker service is available") + b.click("#overview div.pf-v5-c-alert .pf-v5-c-alert__action > button:contains(Start)") + b.wait_not_present("#overview div.pf-v5-c-alert") + is_active_system("active") + is_enabled_system("enabled") + + b.logout() + disable_system() + self.login_and_go("/docker", superuser=False) + b.click("#app .pf-v5-c-empty-state button.pf-m-primary") + b.wait_visible("#containers-containers") + b.wait_not_present("#overview div.pf-v5-c-alert") + + is_active_system("inactive") + is_enabled_system("disabled") + b.logout() + + # no Troubleshoot action without cockpit-system package + disable_system() + self.restore_dir("/usr/share/cockpit/systemd") + self.machine.execute("rm /usr/share/cockpit/systemd/manifest.json") + self.login_and_go("/docker") + b.wait_visible("#app .pf-v5-c-empty-state button.pf-m-primary") + self.assertFalse(b.is_present("#app .pf-v5-c-empty-state button.pf-m-link")) + # starting still works + b.click("#app .pf-v5-c-empty-state button.pf-m-primary") + b.wait_visible("#containers-containers") + + self.allow_restart_journal_messages() + self.allow_journal_messages(".*docker/docker.sock/.*: couldn't connect:.*") + self.allow_journal_messages(".*docker/docker.sock: .*Connection.*Error.*") + self.allow_journal_messages(".*docker/docker.sock/.*/events.*: received truncated HTTP response.*") + + def testCreateContainerSystem(self): + self._testCreateContainer(True) + + def testCreateContainerUser(self): + self._testCreateContainer(False) + + def _testCreateContainer(self, auth): + new_container = 'new-container' + self.execute(True, f"docker run -d --name {new_container} --stop-timeout 0 {IMG_BUSYBOX} touch /latest") + self.execute(True, f"docker commit {new_container} newimage") + new_image_sha = self.execute(True, "docker inspect --format '{{.Id}}' newimage").strip() + + self.execute(True, f"docker run -d -p 5000:5000 --name registry --stop-timeout 0 {IMG_REGISTRY}") + self.execute(True, f"docker run -d -p 6000:5000 --name registry_alt --stop-timeout 0 {IMG_REGISTRY}") + # Add local insecure registry into registries conf + self.machine.write("/etc/containers/registries.conf", REGISTRIES_CONF) + self.execute(True, "systemctl stop docker.service") + # Push busybox image to the local registries + self.execute(True, + f"docker tag {IMG_BUSYBOX} localhost:5000/my-busybox; docker push localhost:5000/my-busybox") + self.execute(True, + f"docker tag {IMG_BUSYBOX} localhost:6000/my-busybox; docker push localhost:6000/my-busybox") + # Untag busybox image which duplicates the image we are about to download + self.execute(True, f"docker rmi -f {IMG_BUSYBOX} localhost:5000/my-busybox localhost:6000/my-busybox") + + self.login(auth) + + b = self.browser + container_name = "busybox-downloaded" + + b.click("#containers-containers button.pf-v5-c-button.pf-m-primary") + b.set_input_text("#run-image-dialog-name", container_name) + + # Test invalid input + b.set_input_text("#create-image-image-select-typeahead", "|alpi*ne?\\") + b.wait_text("button.pf-v5-c-select__menu-item:not(.pf-m-disabled)", "localhost/test-alpine:latest") + + # No local results found + b.set_input_text("#create-image-image-select-typeahead", "notfound") + + b.click('button.pf-v5-c-toggle-group__button:contains("Local")') + b.wait_text("button.pf-v5-c-select__menu-item.pf-m-disabled", "No images found") + + # Local results found + b.set_input_text("#create-image-image-select-typeahead", "registry") + if auth: + b.assert_pixels(".pf-v5-c-modal-box", "image-select", skip_layouts=["rtl"]) + b.click('button.pf-v5-c-toggle-group__button:contains("Local")') + b.wait_text("button.pf-v5-c-select__menu-item", IMG_REGISTRY_LATEST) + + # Local registry + b.set_input_text("#create-image-image-select-typeahead", "my-busybox") + b.click('button.pf-v5-c-toggle-group__button:contains("localhost:5000")') + b.wait_text("button.pf-v5-c-select__menu-item:not(.pf-m-disabled)", "localhost:5000/my-busybox") + + # Select image + b.click('button.pf-v5-c-select__menu-item:contains("localhost:5000/my-busybox")') + + # Remote image, no pull latest image option + b.wait_not_present("#run-image-dialog-pull-latest-image") + + # Create Container, image is pulled and should end up being "running" + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + sel = " span:not(.downloading)" + b.wait(lambda: self.getContainerAttr(container_name, "State", sel) in 'Running') + self.execute(auth, f"docker exec {container_name} test ! -e /latest") + + # Now that we have downloaded an image, verify that selecting download latest image + # downloads the latest image we now push to the registry. Note this image has a /latest file + # to differnatiate it from the other local image. + self.execute(True, f"docker push {new_image_sha} localhost:5000/my-busybox") + self.execute(True, f"docker push {new_image_sha} localhost:6000/my-busybox") + self.execute(True, f"docker rmi {new_image_sha}") + + container_name = "busybox-latest" + + b.click("#containers-containers button.pf-v5-c-button.pf-m-primary") + b.set_input_text("#run-image-dialog-name", container_name) + + # Local registry + b.set_input_text("#create-image-image-select-typeahead", "my-busybox") + b.click('button.pf-v5-c-toggle-group__button:contains("Local")') + + # Select image + b.click('button.pf-v5-c-select__menu-item:contains("localhost:5000/my-busybox")') + + # Pull the latest image + b.set_checked("#run-image-dialog-pull-latest-image", True) + + # Create Container, image is pulled and should end up being "running" + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + sel = " span:not(.downloading)" + b.wait(lambda: self.getContainerAttr(container_name, "State", sel) in 'Running') + # Verify that the latest file exists + output = self.execute(auth, f"docker exec {container_name} ls -lh /latest").strip() + self.assertNotIn("No such file or directory", output) + + # Test creating a container with + if auth: + container_name = "busybox-download-admin" + b.click("#containers-containers button.pf-v5-c-button.pf-m-primary") + + # Start container as admin + b.click('#run-image-dialog-owner-user') + + # Create Container, image is pulled and should end up being "Running" + b.set_input_text("#run-image-dialog-name", container_name) + + b.set_input_text("#create-image-image-select-typeahead", IMG_BUSYBOX) + b.click('button.pf-v5-c-toggle-group__button:contains("Local")') + b.click(f'button.pf-v5-c-select__menu-item:contains("{IMG_BUSYBOX}")') + + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + b.wait(lambda: self.getContainerAttr(container_name, "State", sel) in 'Running') + + def testRunImageSystem(self): + self._testRunImage(True) + + def testRunImageUser(self): + self._testRunImage(False) + + def _testRunImage(self, auth): + b = self.browser + m = self.machine + + # Just drop user images so we can use simpler selectors + if auth: + self.execute(False, "docker rmi --all") + + self.login(auth) + + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + b.wait_in_text("#containers-images", IMG_BUSYBOX) + b.wait_in_text("#containers-images", IMG_ALPINE) + if auth: + b.wait_not_in_text("#containers-images", "admin") + + # Check command in alpine + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_ALPINE}")') + b.click(f'#containers-images tbody tr:contains("{IMG_ALPINE}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + # depending on the precise container, this can be /bin/sh or /bin/ash + cmd = self.execute(auth, 'docker image inspect --format "{{.Config.Cmd}}" ' + IMG_ALPINE) + cmd = cmd.strip().replace('[', '').replace(']', '') + b.wait_attr("#run-image-dialog-command", "value", cmd) + b.click(".btn-cancel") + + # Open run image dialog + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + # Inspect and fill modal dialog + b.wait_val("#create-image-image-select-typeahead", IMG_BUSYBOX_LATEST) + + # Check that there is autogenerated name and then overwrite it + b.wait_not_val("#run-image-dialog-name", "") + b.set_input_text("#run-image-dialog-name", "busybox-with-tty") + + b.wait_visible("#run-image-dialog-command[value='sh']") + + # Check memory configuration + # Only works with CGroupsV2 + if auth or self.has_cgroupsV2: + b.set_checked("#run-image-dialog-memory-limit-checkbox", True) + b.wait_visible("#run-image-dialog-memory-limit-checkbox:checked") + b.wait_visible('#run-image-dialog-memory-limit input[value="512"]') + b.set_input_text("#run-image-dialog-memory-limit input[type=number]", "0.5") + b.set_val('#memory-unit-select', "GB") + + # CPU shares work only with system containers + if auth: + # Check that the checkbox is enabled when clicked on the field + b.wait_visible("#run-image-dialog-cpu-priority-checkbox:not(:checked)") + b.click('#run-image-cpu-priority') + b.wait_visible("#run-image-dialog-cpu-priority-checkbox:checked") + b.set_checked("#run-image-dialog-cpu-priority-checkbox", False) + + b.set_checked("#run-image-dialog-cpu-priority-checkbox", True) + b.wait_visible("#run-image-dialog-cpu-priority-checkbox:checked") + b.wait_visible('#run-image-dialog-cpu-priority input[value="1024"]') + b.set_input_text("#run-image-dialog-cpu-priority input[type=number]", "512") + else: + b.wait_not_present("#run-image-dialog-cpu-priority-checkbox") + + # Enable tty + b.set_checked("#run-image-dialog-tty", True) + + # Set up command line + b.set_input_text('#run-image-dialog-command', + "sh -c 'for i in $(seq 20); do sleep 1; echo $i; done; sleep infinity'") + + if auth: + # Set restart policy to 3 retries + b.set_val("#run-image-dialog-restart-policy", "on-failure") + b.set_input_text('#run-image-dialog-restart-retries input', '3') + else: # no lingering enabled so it's disabled + b.wait_not_present("#run-image-dialog-restart-policy") + + # Switch to Integration tab + b.click("#pf-tab-1-create-image-dialog-tab-integration") + + # Configure published ports + b.click('.publish-port-form .btn-add') + b.set_input_text('#run-image-dialog-publish-0-host-port', '6000') + b.set_input_text('#run-image-dialog-publish-0-container-port', '5000') + b.click('.publish-port-form .btn-add') + b.set_input_text('#run-image-dialog-publish-1-ip-address', '127.0.0.1') + b.set_input_text('#run-image-dialog-publish-1-host-port', '6001') + b.set_input_text('#run-image-dialog-publish-1-container-port', '5001') + b.set_val('#run-image-dialog-publish-1-protocol', "udp") + b.click('.publish-port-form .btn-add') + b.set_input_text('#run-image-dialog-publish-2-ip-address', '7001') + b.set_input_text('#run-image-dialog-publish-2-host-port', '7001') + b.click('#run-image-dialog-publish-2-btn-close') + b.click('.publish-port-form .btn-add') + b.set_input_text('#run-image-dialog-publish-3-container-port', '8001') + b.click('.publish-port-form .btn-add') + b.set_input_text('#run-image-dialog-publish-4-ip-address', '127.0.0.2') + b.set_input_text('#run-image-dialog-publish-4-container-port', '9001') + + # Configure env + b.click('.env-form .btn-add') + b.set_input_text('#run-image-dialog-env-0-key', 'APPLE') + b.set_input_text('#run-image-dialog-env-0-value', 'ORANGE') + b.click('.env-form .btn-add') + b.set_input_text('#run-image-dialog-env-1-key', 'PEAR') + b.set_input_text('#run-image-dialog-env-1-value', 'BANANA') + b.click('.env-form .btn-add') + b.set_input_text('#run-image-dialog-env-2-key', 'MELON') + b.set_input_text('#run-image-dialog-env-2-value', 'GRAPE') + b.click('#run-image-dialog-env-2-btn-close') + b.click('.env-form .btn-add') + # Test inputting an key=var entry + b.set_val('#run-image-dialog-env-3-value', + "RHUBARB=STRAWBERRY DURIAN=LEMON TEST_URL=wss://cockpit/?start=1&stop=0") + # set_val does not trigger onChange so append a space. + b.set_input_text('#run-image-dialog-env-3-value', ' ', append=True, value_check=False) + + b.click('.env-form .btn-add') + b.set_input_text('#run-image-dialog-env-6-key', 'HOSTNAME') + b.set_input_text('#run-image-dialog-env-6-value', 'busybox') + + # Test inputting a var with = in it doesn't reset key + b.click('.env-form .btn-add') + b.set_input_text('#run-image-dialog-env-7-key', 'TEST') + b.set_input_text('#run-image-dialog-env-7-value', 'REBASE=1') + + # Configure volumes + b.click('.volume-form .btn-add') + rodir, rwdir = m.execute("mktemp; mktemp").split('\n')[:2] + m.execute(f"chown admin:admin {rodir}") + m.execute(f"chown admin:admin {rwdir}") + b.set_checked("#run-image-dialog-volume-0-mode", False) + + if self.has_selinux: + b.set_val('#run-image-dialog-volume-0-selinux', "z") + else: + b.wait_not_present('#run-image-dialog-volume-0-selinux') + + b.set_file_autocomplete_val("#run-image-dialog-volume-0 .pf-v5-c-select", rodir) + b.key_press(["\r"]) + b.set_input_text('#run-image-dialog-volume-0-container-path', '/tmp/ro') + ro_label = m.execute(f"ls -dZ {rodir}").split(" ")[0] + b.key_press(["\r"]) + b.click('.volume-form .btn-add') + b.wait_visible('#run-image-dialog-volume-1') + b.click('#run-image-dialog-volume-1-btn-close') + b.wait_not_present('#run-image-dialog-volume-1') + b.click('.volume-form .btn-add') + + if auth: + b.assert_pixels(".pf-v5-c-modal-box", "integration", + ignore=["#run-image-dialog-volume-0 .pf-v5-c-select__toggle-typeahead"], + skip_layouts=["rtl"]) + + if self.has_selinux: + b.set_val('#run-image-dialog-volume-2-selinux', "Z") + else: + b.wait_not_present('#run-image-dialog-volume-2-selinux') + + b.set_file_autocomplete_val("#run-image-dialog-volume-2 .pf-v5-c-select", rwdir) + b.key_press(["\r"]) + b.set_input_text('#run-image-dialog-volume-2-container-path', '/tmp/rw') + rw_label = m.execute(f"ls -dZ {rwdir}").split(" ")[0] + + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + b.wait_not_present("div.pf-v5-c-modal-box") + self.waitContainerRow(IMG_BUSYBOX) + sha = self.execute(auth, "docker inspect --format '{{.Id}}' busybox-with-tty").strip() + self.waitContainer(sha, auth, name='busybox-with-tty', image=IMG_BUSYBOX, + cmd='sh -c "for i in $(seq 20); do sleep 1; echo $i; done; sleep infinity"', + state='Running', owner="system" if auth else "admin") + hasTTY = self.execute(auth, "docker inspect --format '{{.Config.Tty}}' busybox-with-tty").strip() + self.assertEqual(hasTTY, 'true') + # Only works with CGroupsV2 + if auth or self.has_cgroupsV2: + memory = self.execute(auth, "docker inspect --format '{{.HostConfig.Memory}}' busybox-with-tty").strip() + self.assertEqual(memory, '500000000') + + if auth: + cpuShares = self.execute(auth, + "docker inspect --format '{{.HostConfig.CpuShares}}' busybox-with-tty").strip() + self.assertEqual(cpuShares, '512') + + restartPolicy = self.getRestartPolicy(auth, "busybox-with-tty") + if auth: + self.assertEqual(restartPolicy, '{on-failure 3}') + else: + # No restart policy + # format changed in podman 5.1 (https://github.com/containers/podman/pull/22322) + self.assertIn(restartPolicy, ['{ 0}', '{no 0}']) + + b.wait(lambda: "3" in self.execute(auth, "docker logs busybox-with-tty")) + + self.toggleExpandedContainer(IMG_BUSYBOX) + + b.wait_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Created") + dd', 'today at') + + b.click(".pf-m-expanded button:contains('Integration')") + + b.wait_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Ports") + dd', + '0.0.0.0:6000 \u2192 5000/tcp') + b.wait_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Ports") + dd', + '127.0.0.1:6001 \u2192 5001/udp') + b.wait_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Ports") + dd', + '127.0.0.2:') + b.wait_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Ports") + dd', + ' \u2192 8001/tcp') + b.wait_not_in_text(f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Ports") + dd', + '7001/tcp') + + ports = self.execute(auth, "docker inspect --format '{{.NetworkSettings.Ports}}' busybox-with-tty") + self.assertIn('5000/tcp:[{ 6000}]', ports) + self.assertIn('5001/udp:[{127.0.0.1 6001}]', ports) + self.assertIn('8001/tcp:[{', ports) + self.assertIn('9001/tcp:[{127.0.0.2 ', ports) + self.assertNotIn('7001/tcp', ports) + + env_select = f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Environment variables") + dd' + b.wait_in_text(env_select, 'APPLE=ORANGE') + b.wait_in_text(env_select, 'PEAR=BANANA') + b.wait_in_text(env_select, 'RHUBARB=STRAWBERRY') + b.wait_in_text(env_select, 'DURIAN=LEMON') + b.wait_in_text(env_select, 'TEST_URL=wss://cockpit/?start=1&stop=0') + b.wait_in_text(env_select, 'HOSTNAME=busybox') + b.wait_in_text(env_select, 'TEST=REBASE=1') + # variables are present in env but are not displayed in the UI + b.wait_not_in_text(env_select, 'container=docker') + b.wait_not_in_text(env_select, 'TERM=xterm') + b.wait_not_in_text(env_select, 'HOME=/root') + b.wait_not_in_text(env_select, 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin') + + b.click(".container-integration button:contains('Show more')") + # previously hidden variables are now visible + b.wait_in_text(env_select, 'container=docker') + b.wait_in_text(env_select, 'TERM=xterm') + b.wait_in_text(env_select, 'HOME=/root') + b.wait_in_text(env_select, 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin') + + env = self.execute(auth, "docker exec busybox-with-tty env") + self.assertIn('APPLE=ORANGE', env) + self.assertIn('PEAR=BANANA', env) + self.assertIn('RHUBARB=STRAWBERRY', env) + self.assertIn('DURIAN=LEMON', env) + self.assertIn('HOSTNAME=busybox', env) + self.assertIn('TEST=REBASE=1', env) + self.assertIn('container=docker', env) + self.assertIn('TERM=xterm', env) + self.assertIn('HOME=/root', env) + self.assertIn('PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', env) + self.assertNotIn('MELON=GRAPE', env) + + vol_select = f'#containers-containers tr:contains("{IMG_BUSYBOX}") dt:contains("Volumes") + dd' + b.wait_in_text(vol_select, f"{rodir} \u2192 /tmp/ro") + b.wait_in_text(vol_select, f"{rwdir} \u2194 /tmp/rw") + + romnt = self.execute(auth, "docker exec busybox-with-tty cat /proc/self/mountinfo | grep /tmp/ro") + self.assertIn('ro', romnt) + self.assertIn(rodir[4:], romnt) + rwmnt = self.execute(auth, "docker exec busybox-with-tty cat /proc/self/mountinfo | grep /tmp/rw") + self.assertIn('rw', rwmnt) + self.assertIn(rwdir[4:], rwmnt) + + if self.has_selinux: + # rw was set to :Z so it should change, but not be shared + rw_label_new = m.execute(f"ls -dZ {rwdir}").split(" ")[0] + self.assertNotEqual(rw_label, rw_label_new) + self.assertRegex(rw_label_new, r"container_file_t:s0:c\d*,c\d*$") + + # ro was set to :z to it should change and be shared + ro_label_new = m.execute(f"ls -dZ {rodir}").split(" ")[0] + self.assertNotEqual(ro_label, ro_label_new) + self.assertRegex(ro_label_new, "container_file_t:s0$") + + def get_int(n): + try: + return int(n) + except ValueError: + return 0 + + b.wait_not_present("button:contains('Health check logs')") + b.click(".pf-m-expanded button:contains('Logs')") + b.wait_text(".pf-m-expanded .container-logs .xterm-accessibility-tree > div:nth-child(1)", "1") + + # firefox optimizes these out when not visible + b.eval_js(""" + document.querySelector('.pf-m-expanded .container-logs .xterm-accessibility-tree').scrollIntoView() + """) + b.wait_in_text(".pf-m-expanded .container-logs .xterm-accessibility-tree", "6") + + b.click(".pf-m-expanded button:contains('Console')") + b.wait(lambda: + get_int(b.text(".pf-m-expanded .container-terminal .xterm-accessibility-tree > div:nth-child(3)")) > 7) + + # Create another instance without port publishing + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + self.toggleExpandedContainer(IMG_BUSYBOX) + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + b.wait_val("#create-image-image-select-typeahead", IMG_BUSYBOX_LATEST) + b.set_input_text("#run-image-dialog-name", "busybox-without-publish") + + # Set up command line + b.set_input_text('#run-image-dialog-command', + "sh -c 'for i in $(seq 20); do echo $i; sleep 3; done; sleep infinity'") + + # Run without tty, console should be able to `exec` + b.set_checked("#run-image-dialog-tty", False) + + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + b.wait_not_present("div.pf-v5-c-modal-box") + + self.waitContainerRow("busybox-without-publish") + self.toggleExpandedContainer("busybox-without-publish") + b.wait_not_present(""" + #containers-containers tbody tr:contains("busybox-without-publish") + tr dt:contains("Ports") + """) + + # Rootless only works with CGroupsV2 + if auth or self.has_cgroupsV2: + cpuShares = self.execute(auth, """ + docker inspect --format '{{.HostConfig.CpuShares}}' busybox-without-publish + """).strip() + # docker ≥ 1.8 translates 0 default into actual value + self.assertIn(cpuShares, ['0', '1024']) + + b.set_val("#containers-containers-filter", "all") + + b.click(".pf-m-expanded button:contains('Console')") + b.wait_in_text(".pf-m-expanded .xterm-accessibility-tree", "/ # ") + b.focus(".pf-m-expanded .xterm-helper-textarea") + b.key_press('clear\r') + b.wait_not_in_text(".pf-m-expanded .xterm-accessibility-tree", "clear") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(1)", "/ # ") + b.key_press('echo hello\r') + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(2)", "hello") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(3)", "/ # ") + b.wait_text(".pf-m-expanded .xterm-accessibility-tree > div:nth-child(1)", "/ # echo hello") + + b.go("#/?name=tty") + self.check_containers(["busybox-with-tty"], ["busybox-without-publish"]) + b.go("#/?name=busy") + self.check_containers(["busybox-with-tty", "busybox-without-publish"], []) + + b.set_input_text('#containers-filter', 'tty') + self.check_containers(["busybox-with-tty"], ["busybox-without-publish"]) + self.check_images([], [IMG_ALPINE, IMG_BUSYBOX, IMG_REGISTRY]) + b.set_input_text('#containers-filter', 'busy') + b.wait_js_cond('window.location.hash === "#/?name=busy"') + self.check_containers(["busybox-with-tty", "busybox-without-publish"], []) + self.check_images([IMG_BUSYBOX], [IMG_ALPINE, IMG_REGISTRY]) + b.set_input_text('#containers-filter', 'alpine') + b.wait_js_cond('window.location.hash === "#/?name=alpine"') + self.check_containers([], ["busybox-with-tty", "busybox-without-publish"]) + self.check_images([IMG_ALPINE], [IMG_BUSYBOX, IMG_REGISTRY]) + b.set_input_text('#containers-filter', '') + self.check_containers(["busybox-with-tty", "busybox-without-publish"], []) + self.check_images([IMG_ALPINE, IMG_BUSYBOX, IMG_REGISTRY], []) + b.wait_js_cond('window.location.hash === "#/"') + + self.filter_containers("running") + id_with_tty = self.execute(auth, "docker inspect --format '{{.Id}}' busybox-with-tty").strip() + + container_sel = f'#containers-images tbody tr:contains("{IMG_BUSYBOX}")' + b.click(f'{container_sel} td.pf-v5-c-table__toggle button') + # running container, just selects it, but leaves "Only running" alone + b.click(f"{container_sel} + tr div.ct-listing-panel-body dt:contains('Used by') + dd button:contains('busybox-with-tty')") # noqa: E501 + b.wait_js_cond('window.location.hash === "#' + id_with_tty + '"') + b.wait_val("#containers-containers-filter", "running") + # FIXME: expanding running container details does not actually work right now + # b.wait_in_text("#containers-containers tr.pf-m-expanded .container-details", "sleep infinity") + # stopped container, switches to showing all containers + + # Create a container without starting it + self.filter_containers("all") + container_name = "busybox-not-started" + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + b.wait_val("#create-image-image-select-typeahead", IMG_BUSYBOX_LATEST) + b.set_input_text("#run-image-dialog-name", container_name) + b.set_input_text("#run-image-dialog-command", "sh -c sleep infinity") + + b.click('.pf-v5-c-modal-box__footer #create-image-create-btn') + b.wait_not_present("div.pf-v5-c-modal-box") + + sha = self.execute(auth, "docker inspect --format '{{.Id}}' " + container_name).strip() + self.waitContainer(sha, auth, name=container_name, image=IMG_BUSYBOX, state=['Configured', 'Created']) + + self.filter_containers("running") + b.wait_not_in_text("#containers-containers", "busybox-not-started") + container_sel = f"#containers-images tbody tr:contains('{IMG_BUSYBOX}') + tr div.ct-listing-panel-body" + b.click(f"{container_sel} dt:contains('Used by') + dd button:contains('busybox-not-started')") + b.wait_js_cond(f"window.location.hash === '#{sha}'") + b.wait_val("#containers-containers-filter", "all") + b.wait_in_text("#containers-containers", "busybox-not-started") + # auto-expands container details + b.wait_in_text("#containers-containers tbody tr:contains('busybox-not-started') + tr", "sleep infinity") + + b.click(f'#containers-images tbody tr:contains("{IMG_ALPINE}") td.pf-v5-c-table__toggle button') + b.wait_in_text(f"#containers-images tbody tr:contains('{IMG_ALPINE}') td[data-label='Used by']", 'unused') + + b.set_input_text('#containers-filter', 'foobar') + b.wait_in_text('#containers-containers .pf-v5-c-empty-state', 'No containers that match the current filter') + b.wait_in_text('#containers-images .pf-v5-c-empty-state', 'No images that match the current filter') + b.set_input_text('#containers-filter', '') + + if not auth or not self.machine.ostree_image: # don't kill ws container + # Ubuntu 22.04 has old docker that does not know about --time + if m.image != 'ubuntu-2204': + # Remove all containers first as it is not possible to set --time 0 to rmi command + self.execute(auth, "docker rm --all --force --time 0") + self.execute(auth, "docker rmi -af") + b.wait_in_text('#containers-containers .pf-v5-c-empty-state', 'No containers') + b.set_val("#containers-containers-filter", "running") + b.wait_in_text('#containers-containers .pf-v5-c-empty-state', 'No running containers') + b.wait_in_text('#containers-images .pf-v5-c-empty-state', 'No images') + + def check_content(self, kind, present, not_present): + b = self.browser + for item in present: + b.wait_visible(f'#containers-{kind} tbody tr:first-child:contains({item})') + for item in not_present: + b.wait_not_present(f'#containers-{kind} tbody tr:first-child:contains({item})') + + def check_containers(self, present, not_present): + self.check_content("containers", present, not_present) + + def check_images(self, present, not_present): + self.check_content("images", present, not_present) + + def waitContainer(self, row_id, auth, name="", image="", cmd="", owner="", state=None, pod="no-pod"): + """Check the container with row_name has the expected values + "image" can be substring, "state" might be string or array of possible states, other are + checked for exact match. + """ + sel = "#containers-containers #table-" + pod + f" tbody tr[data-row-id=\"{row_id}{auth}\"]".lower() + b = self.browser + if name: + b.wait_text(sel + " .container-name", name) + if image: + b.wait_in_text(sel + " .container-block small:nth-child(2)", image) + if cmd: + b.wait_text(sel + " .container-block small:last-child", cmd) + if owner: + if owner == "system": + b.wait_text(sel + " td[data-label=Owner]", owner) + else: + b.wait_text(sel + " td[data-label=Owner]", "user: " + owner) + if state is not None: + if not isinstance(state, list): + state = [state] + b.wait(lambda: b.text(sel + " td[data-label=State]") in state) + + def filter_containers(self, value): + """Use dropdown menu in the header to filter containers""" + b = self.browser + b.set_val("#containers-containers-filter", value) + + def confirm_modal(self, text): + """Wait for the pop up window and click the button with text""" + b = self.browser + b.click(f".pf-v5-c-modal-box footer button:contains({text})") + b.wait_not_present(f".pf-v5-c-modal-box footer button:contains({text})") + + def testPruneUnusedImagesSystem(self): + self._testPruneUnusedImagesSystem(True) + + def testPruneUnusedImagesUser(self): + self._testPruneUnusedImagesSystem(False) + + @testlib.skipOstree("no root login available on ostree") + def testPruneUnusedImagesRoot(self): + self._testPruneUnusedImagesSystem(False, True) + + def _testPruneUnusedImagesSystem(self, auth, root=False): + b = self.browser + if root: + self.login_and_go("/docker", user="root", enable_root_login=True) + b.wait_visible("#app") + else: + self.login(auth) + + leftover_images = 1 + # cockpit-ws image + if self.machine.ostree_image and auth: + leftover_images += 1 + + # By default we have 3 unused images, start one. + self.execute(auth or root, f"docker run -d --name used_image --stop-timeout 0 {IMG_ALPINE} sh") + b.click("#image-actions-dropdown") + b.click("#prune-unused-images-button") + + if auth: + b.wait_js_func("ph_count_check", ".pf-v5-c-modal-box__body .pf-v5-c-list li", + (self.user_images_count + self.system_images_count) - leftover_images) + elif root: + b.wait_js_func("ph_count_check", ".pf-v5-c-modal-box__body .pf-v5-c-list li", + self.system_images_count - leftover_images) + else: + b.wait_js_func("ph_count_check", ".pf-v5-c-modal-box__body .pf-v5-c-list li", + self.user_images_count - leftover_images) + b.click(".pf-v5-c-modal-box button:contains(Prune)") + + # When being superuser, admin images are also removed + if auth: + self.waitNumImages(leftover_images) + checkImage(b, IMG_ALPINE, "system") + else: + self.waitNumImages(leftover_images) + # Two images removed, one in use kept + b.wait_not_present(f"#containers-images:contains('{IMG_BUSYBOX}')") + b.wait_not_present(f"#containers-images:contains('{IMG_REGISTRY}')") + b.wait_visible(f"#containers-images:contains('{IMG_ALPINE}')") + + # Prune button should now be disabled + b.click("#image-actions-dropdown") + b.wait_visible(".pf-m-disabled.pf-v5-c-menu__list-item:contains(Prune unused images)") + + def testPruneUnusedImagesSystemSelections(self): + """ Test the prune unused images selection options""" + b = self.browser + self.login(True) + + b.click("#image-actions-dropdown") + b.click("button:contains(Prune unused images)") + + # Deselect both + b.click("#deleteSystemImages") + b.click("#deleteUserImages") + b.wait_visible(".pf-v5-c-modal-box button:contains(Prune):disabled") + + # Admin / user images are selected + expected_images = self.user_images_count + self.system_images_count + if self.machine.ostree_image: + expected_images -= 1 + b.wait_js_func("ph_count_check", ".pf-v5-c-modal-box__body .pf-v5-c-list li", expected_images) + # Select user images + b.click("#deleteUserImages") + b.click(".pf-v5-c-modal-box button:contains(Prune)") + + # System images are left over + self.waitNumImages(self.system_images_count) + checkImage(b, IMG_ALPINE, "system") + checkImage(b, IMG_BUSYBOX, "system") + checkImage(b, IMG_REGISTRY, "system") + + # Pruning again, should delete all system images + b.click("#image-actions-dropdown") + b.click("button:contains(Prune unused images)") + b.wait_js_func("ph_count_check", ".pf-v5-c-modal-box__body .pf-v5-c-list li", + self.system_images_count - 1 if self.machine.ostree_image else self.system_images_count) + b.click(".pf-v5-c-modal-box button:contains(Prune)") + self.waitNumImages(1 if self.machine.ostree_image else 0) + + # Prune button should now be disabled + b.click("#image-actions-dropdown") + b.wait_visible(".pf-v5-c-menu__list-item.pf-m-disabled:contains(Prune unused images)") + + def testPruneUnusedContainersSystem(self): + self._testPruneUnusedContainersSystem(True) + + def testPruneUnusedContainersUser(self): + self._testPruneUnusedContainersSystem(False) + + def _testPruneUnusedContainersSystem(self, auth): + """Test the prune unused container image dialog""" + + b = self.browser + self.login(auth) + + # Create running and non-running containers + self.execute(auth, "docker pod create --name pod") + notrunninginpodId = self.execute(auth, f""" + docker run --name inpod --pod pod -tid {IMG_BUSYBOX} sh -c 'exit 1'""").strip() + runninginpodId = self.execute(auth, f""" + docker run --name inpodrunning --pod pod -tid {IMG_BUSYBOX} sh -c 'sleep infinity'""").strip() + + self.execute(auth, f"docker run --name notrunning -tid {IMG_BUSYBOX} sh -c 'exit 1'") + self.execute(auth, f"docker run --name containerrunning -tid {IMG_BUSYBOX} sh -c 'sleep infinity'") + + # Create containers for the opposite of what we are, admin or super admin + if auth: + self.execute(False, f"docker run --name adminnotrunning -tid {IMG_BUSYBOX} sh 'exit 1'") + b.wait(lambda: self.getContainerAttr("adminnotrunning", "State") in NOT_RUNNING) + self.execute(False, f"docker run --name adminrunning -tid {IMG_BUSYBOX} sh -c 'sleep infinity'") + b.wait(lambda: self.getContainerAttr("adminrunning", "State") == "Running") + + b.click("#containers-actions-dropdown") + b.click("button:contains(Prune unused containers)") + + if auth: + b.wait_in_text(".pf-v5-c-modal-box__body tbody:nth-of-type(1) td[data-label=Name]", "adminnotrunning") + b.wait_in_text(".pf-v5-c-modal-box__body tbody:nth-of-type(2) td[data-label=Name]", "notrunning") + else: + b.wait_in_text(".pf-v5-c-modal-box__body tbody td[data-label=Name]", "notrunning") + + b.click(".pf-v5-c-modal-box button:contains(Prune)") + b.wait_not_present(".pf-v5-c-modal-box__body") + + if auth: + self.waitContainerRow("notrunning", False) + self.waitContainerRow("adminnotrunning", False) + else: + self.waitContainerRow("notrunning", False) + + # Verify running containers still exists + self.waitContainerRow("containerrunning") + pods = [{"name": "inpod", "state": "Exited", "id": notrunninginpodId, + "image": IMG_BUSYBOX, "command": 'sh -c "exit 1"'}, + {"name": "inpodrunning", "state": "Running", "id": runninginpodId, + "image": IMG_BUSYBOX, "command": 'sh -c "sleep infinity"'}] + self.waitPodContainer("pod", pods, auth) + + def testCreateContainerValidation(self): + def validateField(groupSelector, value, errorMessage, resetValue=""): + b.set_input_text(f"{groupSelector} input", value) + b.wait_visible(".pf-v5-c-modal-box__footer #create-image-create-run-btn:not(:disabled)") + b.wait_in_text(f"{groupSelector} .pf-v5-c-helper-text__item-text", errorMessage) + b.wait_visible(".pf-v5-c-modal-box__footer #create-image-create-run-btn[aria-disabled=true]") + # Reset to acceptable value and verify the validation message is not present + b.set_input_text(f"{groupSelector} input", resetValue) + b.wait_not_present(f"{groupSelector} .pf-v5-c-helper-text__item-text") + b.wait_visible(".pf-v5-c-modal-box__footer #create-image-create-run-btn:not(:disabled)") + + # Test the validation errors + + # complaint about port conflict + self.allow_browser_errors("error: Container failed to be started:.*") + self.allow_browser_errors("No routable interface.*") + self.allow_browser_errors(".*ddress already in use.*5000.*") + b = self.browser + self.login(False) + container_name = 'portused' + + # Start a docker container which uses a port + self.execute(False, f"docker run -d -p 5000:5000 --name registry --stop-timeout 0 {IMG_REGISTRY}") + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + validateField("#image-name-group", "registry", "Name already in use") + + # Switch to Integration tab + b.click("#pf-tab-1-create-image-dialog-tab-integration") + + # Test validation of port mapping + b.click('.publish-port-form .btn-add') + b.set_input_text("#run-image-dialog-publish-0-container-port-group input", "1") + validateField("#run-image-dialog-publish-0-ip-address-group", "abcd", "valid IP address") + validateField("#run-image-dialog-publish-0-host-port-group", "-1", "1 to 65535") + validateField("#run-image-dialog-publish-0-host-port-group", "99999", "1 to 65535") + validateField("#run-image-dialog-publish-0-container-port-group", "-1", "1 to 65535", resetValue="1") + validateField("#run-image-dialog-publish-0-container-port-group", "", "must not be empty", resetValue="1") + validateField("#run-image-dialog-publish-0-container-port-group", "99999", "1 to 65535", resetValue="1") + + # Test validation of volumes + b.click('.volume-form .btn-add') + b.set_input_text("#run-image-dialog-volume-0-container-path-group input", "/somepath") + validateField("#run-image-dialog-volume-0-container-path-group", "", "not be empty", resetValue="/somepath") + + # Test validation of environment variables + b.click('.env-form .btn-add') + b.set_input_text("#run-image-dialog-env-0-key-group input", "sometext") + validateField("#run-image-dialog-env-0-key-group", "", "must not be empty", resetValue="sometext") + + b.set_input_text("#run-image-dialog-name", container_name) + + # Port address is already in use + b.set_input_text('#run-image-dialog-publish-0-host-port', '5000') + b.set_input_text('#run-image-dialog-publish-0-container-port', '5000') + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + # Can be "[aA]ddress" + b.wait_in_text(".pf-v5-c-alert", "ddress already in use") + + # Changing the port should allow creation of container + b.set_input_text('#run-image-dialog-publish-0-host-port', '5001') + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + b.wait_not_present("#run-image-dialog-name") + + self.waitContainerRow(container_name) + + # Test validation JavaScript errors when removing invalid environment entries + container_name = 'env-var-validation' + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + b.set_input_text("#run-image-dialog-name", container_name) + b.click("#pf-tab-1-create-image-dialog-tab-integration") + + # Make sure our form validation does not crash when adding and removing invalid entries + b.click('.env-form .btn-add') + b.click('.env-form .btn-add') + b.click('.env-form .btn-add') + b.set_input_text("#run-image-dialog-env-1-key-group input", "something") + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + + b.wait_in_text("#run-image-dialog-env-0-key-group .pf-v5-c-helper-text__item-text", "must not be empty") + b.wait_in_text("#run-image-dialog-env-2-key-group .pf-v5-c-helper-text__item-text", "must not be empty") + + # remove invalid entries + b.click('#run-image-dialog-env-0-btn-close') + b.click('#run-image-dialog-env-2-btn-close') + + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + self.waitContainerRow(container_name) + + def _testHealthcheck(self, auth): + b = self.browser + + # Just drop user images so we can use simpler selectors + if auth: + self.execute(False, f"docker rmi {IMG_BUSYBOX}") + + self.login(auth) + + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + b.set_input_text("#run-image-dialog-name", "healthy") + + b.click("#pf-tab-2-create-image-dialog-tab-healthcheck") + b.set_input_text('#run-image-dialog-healthcheck-command', 'true') + b.set_input_text('#run-image-healthcheck-interval input', '325') + b.set_input_text('#run-image-healthcheck-timeout input', '35') + b.set_input_text('#run-image-healthcheck-start-period input', '5') + b.click('#run-image-healthcheck-retries .pf-v5-c-input-group__item:nth-child(1) button') + b.wait_val("#run-image-healthcheck-retries input", 2) + if auth: + b.assert_pixels('.pf-v5-c-modal-box', "healthcheck-modal", skip_layouts=["rtl"]) + # Test that the healthcheck option is not available before docker 4.3 + if docker_version(self) < (4, 3, 0): + b.wait_not_present("#run-image-healthcheck-action") + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + + self.waitContainerRow("healthy") + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + healthy_sha = self.execute(auth, "docker inspect --format '{{.Id}}' healthy").strip() + self.waitContainer(healthy_sha, auth, state='RunningHealthy') + + self.toggleExpandedContainer("healthy") + b.click(".pf-m-expanded button:contains('Health check')") + + b.wait_in_text('#container-details-healthcheck dt:contains("Command") + dd', 'true') + b.wait_in_text('#container-details-healthcheck dt:contains("Interval") + dd', '325 seconds') + b.wait_in_text('#container-details-healthcheck dt:contains("Retries") + dd', '2') + b.wait_in_text('#container-details-healthcheck dt:contains("Timeout") + dd', '35 seconds') + b.wait_in_text('#container-details-healthcheck dt:contains("Start period") + dd', '5 seconds') + b.wait_not_present('#container-details-healthcheck dt:contains("Failing streak")') + if docker_version(self) >= (4, 3, 0): + b.wait_in_text('#container-details-healthcheck dt:contains("When unhealthy") + dd', 'No action') + + self.assertEqual(self.execute(auth, "docker inspect --format '{{.Config.Healthcheck}}' healthy").strip(), + "{[true] 5s 5m25s 35s 2}") + + # single successful health check + b.wait_in_text(".ct-listing-panel-body tbody tr", "Passed health run") + b.wait_visible(".ct-listing-panel-body tbody:nth-of-type(1) svg.green") + b.wait_not_present(".ct-listing-panel-body tbody:nth-of-type(2)") + + # Trigger run manually, adds one more healthy run + self.performContainerAction("healthy", "Run health check") + b.wait_visible(".ct-listing-panel-body tbody:nth-of-type(2) svg.green") + b.wait_not_present(".ct-listing-panel-body tbody:nth-of-type(3)") + + self.toggleExpandedContainer("healthy") + + self.execute(auth, f"docker run --name sick -dt --health-cmd false --health-interval 5s {IMG_BUSYBOX}") + self.waitContainerRow("sick") + unhealthy_sha = self.execute(auth, "docker inspect --format '{{.Id}}' sick").strip() + self.waitContainer(unhealthy_sha, auth, state='RunningUnhealthy') + # Unhealthy should be first + expected_ws = "" + if auth and self.machine.ostree_image: + expected_ws = "ws" + b.wait_collected_text("#containers-containers .container-name", "healthysick" + expected_ws) + + self.toggleExpandedContainer("sick") + b.click(".pf-m-expanded button:contains('Health check')") + b.wait_visible(".pf-m-expanded .ct-listing-panel-body tbody:nth-of-type(1)") + b.wait_visible(".pf-m-expanded .ct-listing-panel-body tbody:nth-of-type(4)") + b.wait_visible(".pf-m-expanded .ct-listing-panel-body tbody:nth-of-type(2) svg.red") + b.wait_visible('.pf-m-expanded #container-details-healthcheck dt:contains("Failing streak")') + failures = int(b.text('.pf-m-expanded #container-details-healthcheck dt:contains("Failing streak") + dd')) + self.assertGreater(failures, 3) + if auth: + b.wait_js_func("ph_count_check", ".pf-m-expanded table[aria-label=Logs] tbody tr", 5) + b.assert_pixels(".pf-m-expanded .pf-v5-c-table__expandable-row-content", + "healthcheck-details", + ignore=["thead", "#container-details-healthcheck dt:contains('Failing streak') + dd", + "td[data-label='Started at']"], + skip_layouts=["rtl"]) + + self.toggleExpandedContainer("sick") + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + b.wait_visible('#containers-images td[data-label="Image"]:contains("busybox:latest")') + b.click('#containers-images tbody tr:contains("busybox:latest") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + # Test the health check action, only supported in docker 4.3 and later. + # To test this we make a healthcheck which depends on a file, so when starting the + # container is healthy, after we remove the file the healthcheck should fail and our + # configured action should executed. + if docker_version(self) < (4, 3, 0): + return + + containername = "healthaction" + b.set_input_text("#run-image-dialog-name", containername) + b.set_input_text("#run-image-dialog-command", "/bin/sh -c 'echo 1 > /healthy && sleep infinity'") + + b.click("#pf-tab-2-create-image-dialog-tab-healthcheck") + b.set_input_text('#run-image-dialog-healthcheck-command', '/bin/test -f /healthy') + b.set_input_text('#run-image-healthcheck-interval input', '1') + b.set_input_text('#run-image-healthcheck-timeout input', '1') + b.click('#run-image-healthcheck-action-2') + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + + self.waitContainerRow(containername) + self.toggleExpandedContainer(containername) + b.wait(lambda: self.getContainerAttr(containername, "State") == "RunningHealthy") + b.click(".pf-m-expanded button:contains('Health check')") + b.wait_in_text('.pf-m-expanded #container-details-healthcheck dt:contains("When unhealthy") + dd', + 'Force stop') + # Removing the file should kill the container + status = self.execute(auth, f"docker exec {containername} rm -f /healthy").strip() + b.wait(lambda: self.getContainerAttr(containername, + "State", "span:not(.ct-badge-container-unhealthy)") in NOT_RUNNING) + status = self.execute(auth, f"docker inspect --format '{{{{.State.Health.Status}}}}' {containername}").strip() + self.assertEqual(status, "unhealthy") + + def testHealthcheckSystem(self): + self._testHealthcheck(True) + + def testHealthcheckUser(self): + self._testHealthcheck(False) + + + def testdockerRestartEnabledSystem(self): + self._testdockerRestartEnabled(True) + + def _testdockerRestartEnabled(self, auth): + b = self.browser + if auth: + self.addCleanup(self.machine.execute, "systemctl disable docker-restart.service") + + # Drop user images for easy selection + if auth: + self.execute(False, f"docker rmi {IMG_BUSYBOX}") + + self.login(auth) + b.click("#containers-images button.pf-v5-c-expandable-section__toggle") + + def create_container(name, policy=None): + b.wait_visible(f'#containers-images td[data-label="Image"]:contains("{IMG_BUSYBOX}")') + b.click(f'#containers-images tbody tr:contains("{IMG_BUSYBOX}") .ct-container-create') + b.wait_visible('div.pf-v5-c-modal-box header:contains("Create container")') + + b.set_input_text("#run-image-dialog-name", name) + if policy: + b.set_val("#run-image-dialog-restart-policy", "always") + b.click('.pf-v5-c-modal-box__footer #create-image-create-run-btn') + self.waitContainerRow(name) + + container_name = 'none' + create_container(container_name) + # format changed in podman 5.1 (https://github.com/containers/podman/pull/22322) + self.assertIn(self.getRestartPolicy(auth, container_name), ['{ 0}', '{no 0}']) + + container_name = 'restart' + create_container(container_name, 'always') + self.assertEqual(self.getRestartPolicy(auth, container_name), '{always 0}') + if auth: + dockerRestartEnabled = self.execute(True, "systemctl is-enabled docker-restart.service || true").strip() + self.assertEqual(dockerRestartEnabled, 'enabled') + + def testPauseResumeContainerSystem(self): + self._testPauseResumeContainer(True) + + def testPauseResumeContainerUser(self): + # rootless cgroupv1 containers do not support pausing + if not self.has_cgroupsV2: + return + self._testPauseResumeContainer(False) + + def _testPauseResumeContainer(self, auth): + b = self.browser + container_name = "pauseresume" + + self.execute(auth, f"docker run -dt --name {container_name} --stop-timeout 0 {IMG_ALPINE}") + self.login(auth) + + self.waitContainerRow(container_name) + self.toggleExpandedContainer(container_name) + b.wait_not_present(self.getContainerAction(container_name, 'Resume')) + self.performContainerAction(container_name, "Pause") + + # show all containers and check status + self.filter_containers('all') + + # Check that container details are not lost when the container is paused + b.click(".pf-m-expanded button:contains('Integration')") + b.wait_visible(f'#containers-containers tr:contains("{IMG_ALPINE}") dt:contains("Environment variables")') + + b.wait(lambda: self.getContainerAttr(container_name, "State") == "Paused") + b.wait_not_present(self.getContainerAction(container_name, 'Pause')) + self.performContainerAction(container_name, "Resume") + b.wait(lambda: self.getContainerAttr(container_name, "State") == "Running") + + def testRenameContainerSystem(self): + self._testRenameContainer(True) + + def _testRenameContainer(self, auth): + b = self.browser + container_name = "rename" + container_name_new = "rename-new" + + self.execute(auth, f"docker container create -t --name {container_name} {IMG_BUSYBOX}") + self.login(auth) + + self.filter_containers('all') + + self.waitContainerRow(container_name) + self.toggleExpandedContainer(container_name) + self.performContainerAction(container_name, "Rename") + + # the container name should be in the "Rename container" header + b.wait_in_text("#pf-modal-part-1", container_name) + b.set_input_text("#rename-dialog-container-name", "") + b.wait_in_text("#commit-dialog-image-name-helper", "Container name is required") + b.set_input_text("#rename-dialog-container-name", "banana???") + b.wait_in_text("#commit-dialog-image-name-helper", "Name can only contain letters, numbers") + + b.set_input_text("#rename-dialog-container-name", container_name_new) + b.click('#btn-rename-dialog-container') + b.wait_not_present("#rename-dialog-container-name") + + self.execute(auth, f"docker inspect --format '{{{{.Id}}}}' {container_name_new}").strip() + self.waitContainerRow(container_name_new) + + # rename using the enter key + self.toggleExpandedContainer(container_name_new) + self.performContainerAction(container_name_new, "Rename") + + container_name_new = "rename-new-enter" + b.set_input_text("#rename-dialog-container-name", "") + b.focus("#rename-dialog-container-name") + b.key_press("\r") # Simulate enter key + b.wait_in_text("#commit-dialog-image-name-helper", "Container name is required") + b.set_input_text("#rename-dialog-container-name", container_name_new) + b.focus("#rename-dialog-container-name") + b.key_press("\r") # Simulate enter key + b.wait_not_present("#rename-dialog-container-name") + + self.execute(auth, f"docker inspect --format '{{{{.Id}}}}' {container_name_new}").strip() + self.waitContainerRow(container_name_new) + + def testMultipleContainers(self): + self.login() + + # Create 31 containers + for i in range(31): + self.execute(True, f"docker run -dt --name container{i} --stop-timeout 0 {IMG_BUSYBOX}") + + self.waitContainerRow("container30") + + # Generic cleanup takes too long and timeouts, so remove these container manually one by one + for i in range(31): + self.execute(True, f"docker rm -f container{i}") + + def testSpecialContainers(self): + m = self.machine + b = self.browser + + toolbox_label = "com.github.containers.toolbox=true" + distrobox_label = "manager=distrobox" + + container_1_id = m.execute(f"docker run -d --name container_1 -l {toolbox_label} {IMG_BUSYBOX}").strip() + container_2_id = m.execute(f"docker run -d --name container_2 -l {distrobox_label} {IMG_BUSYBOX}").strip() + + self.login() + + self.waitContainerRow('container_1') + self.waitContainerRow('container_2') + + container_1_sel = f"#containers-containers tbody tr[data-row-id=\"{container_1_id}{'true'}\"]" + container_2_sel = f"#containers-containers tbody tr[data-row-id=\"{container_2_id}{'true'}\"]" + + b.wait_visible(container_1_sel + " .ct-badge-toolbox:contains('toolbox')") + b.wait_visible(container_2_sel + " .ct-badge-distrobox:contains('distrobox')") + + # def testCreatePodSystem(self): + # self._createPod(True) + + # def testCreatePodUser(self): + # self._createPod(False) + + # def _createPod(self, auth): + # b = self.browser + # m = self.machine + # pod_name = "testpod1" + + # self.login(auth) + + # b.click("#containers-containers-create-pod-btn") + # b.set_input_text("#create-pod-dialog-name", "") + # b.wait_visible(".pf-v5-c-modal-box__footer #create-pod-create-btn:disabled") + # b.wait_in_text("#pod-name-group .pf-v5-c-helper-text__item-text", "Invalid characters") + + # b.set_input_text("#create-pod-dialog-name", pod_name) + # b.wait_visible(".pf-v5-c-modal-box__footer #create-pod-create-btn:not(:disabled)") + + # b.click('.publish-port-form .btn-add') + # b.set_input_text("#create-pod-dialog-publish-0-container-port-group input", "-1") + # b.click(".pf-v5-c-modal-box__footer #create-pod-create-btn") + # b.wait_in_text("#create-pod-dialog-publish-0-container-port-group .pf-v5-c-helper-text__item-text", + # "1 to 65535") + # b.click("#create-pod-dialog-publish-0-btn-close") + + # if auth: + # b.wait_visible("#create-pod-dialog-owner-system:checked") + # else: + # b.wait_not_present("#create-pod-dialog-owner-system") + + # Ports + # b.click('.publish-port-form .btn-add') + # b.set_input_text('#create-pod-dialog-publish-1-host-port', '6000') + # b.set_input_text('#create-pod-dialog-publish-1-container-port', '5000') + # b.click('.publish-port-form .btn-add') + # b.set_input_text('#create-pod-dialog-publish-2-ip-address', '127.0.0.1') + # b.set_input_text('#create-pod-dialog-publish-2-host-port', '6001') + # b.set_input_text('#create-pod-dialog-publish-2-container-port', '5001') + # b.set_val('#create-pod-dialog-publish-2-protocol', "udp") + # b.click('.publish-port-form .btn-add') + # b.set_input_text('#create-pod-dialog-publish-3-ip-address', '127.0.0.2') + # b.set_input_text('#create-pod-dialog-publish-3-container-port', '9001') + + # Volumes + # if self.machine.image not in ["ubuntu-2204"]: + # b.click('.volume-form .btn-add') + # rodir, rwdir = m.execute("mktemp; mktemp").split('\n')[:2] + # m.execute(f"chown admin:admin {rodir}") + # m.execute(f"chown admin:admin {rwdir}") + + # if self.has_selinux: + # b.set_val('#create-pod-dialog-volume-0-selinux', "z") + # else: + # b.wait_not_present('#create-pod-dialog-volume-0-selinux') + + # b.set_file_autocomplete_val("#create-pod-dialog-volume-0 .pf-v5-c-select", rodir) + # b.set_input_text('#create-pod-dialog-volume-0-container-path', '/tmp/ro') + # b.click('.volume-form .btn-add') + + # b.set_file_autocomplete_val("#create-pod-dialog-volume-1 .pf-v5-c-select", rwdir) + # b.set_input_text('#create-pod-dialog-volume-1-container-path', '/tmp/rw') + + # b.click("#create-pod-create-btn") + # b.set_val("#containers-containers-filter", "all") + # self.waitPodContainer(pod_name, []) + + # container_name = 'test-pod-1-system' if auth else 'test-pod-1' + # cmd = f"docker run -d --pod {pod_name} --name {container_name} --stop-timeout 0 {IMG_ALPINE} sleep 500" + # containerId = self.execute(auth, cmd).strip() + # self.waitPodContainer(pod_name, + # [{"name": container_name, "image": IMG_ALPINE, + # "command": "sleep 500", "state": "Running", "id": containerId}], auth) + + # self.toggleExpandedContainer(container_name) + # b.click(".pf-m-expanded button:contains('Integration')") + # if self.machine.image not in ["ubuntu-2204"]: + # b.wait_in_text('#containers-containers tr:contains("alpine") dt:contains("Volumes") + dd', + # f"{rodir} \u2194 /tmp/ro") + # b.wait_in_text('#containers-containers tr:contains("alpine") dt:contains("Volumes") + dd', + # f"{rwdir} \u2194 /tmp/rw") + + # b.wait_in_text('#containers-containers tr:contains("alpine") dt:contains("Ports") + dd', + # '0.0.0.0:6000 \u2192 5000/tcp') + # b.wait_in_text('#containers-containers tr:contains("alpine") dt:contains("Ports") + dd', + # '127.0.0.1:6001 \u2192 5001/udp') + # b.wait_in_text('#containers-containers tr:contains("alpine") dt:contains("Ports") + dd', + # ' \u2192 9001/tcp') + + + # Create pod as admin + # if auth: + # pod_name = 'testpod2' + # b.click("#containers-containers-create-pod-btn") + # b.set_input_text("#create-pod-dialog-name", pod_name) + # b.click("#create-pod-dialog-owner-user") + # b.click("#create-pod-create-btn") + + # b.set_val("#containers-containers-filter", "all") + # self.waitPodContainer(pod_name, []) + + @testlib.skipImage("passthrough log driver not supported", "ubuntu-2204") + def testLogErrors(self): + b = self.browser + container_name = "logissue" + self.login() + + self.execute(False, + f"docker run --log-driver=passthrough --name {container_name} -d {IMG_ALPINE} false /etc/sysctl.d/00-local-userns.conf + systemctl restart systemd-sysctl + + # disable services that get in the way of /var/lib/containers + if systemctl is-enabled docker.service; then + systemctl disable docker.service + fi +fi + +# don't force https:// (self-signed cert) +mkdir -p /etc/cockpit +printf "[WebService]\\nAllowUnencrypted=true\\n" > /etc/cockpit/cockpit.conf + +if systemctl is-active -q firewalld.service; then + firewall-cmd --add-service=cockpit --permanent +fi + +. /usr/lib/os-release + +# Remove extra images, tests assume our specific set +# Since 4.0 docker now ships the pause image +docker images --format '{{.Repository}}:{{.Tag}}' | grep -Ev 'localhost/test-|pause|cockpit/ws' | xargs -r docker rmi -f + +# tests reset podman, save the images +mkdir -p /var/lib/test-images +for img in $(podman images --format '{{.Repository}}:{{.Tag}}'); do + fname="$(echo "$img" | tr -dc '[a-zA-Z-]')" + podman save -o "/var/lib/test-images/${fname}.tar" "$img" +done + +# 15minutes after boot tmp files are removed and docker stores some tmp lock files +systemctl disable --now systemd-tmpfiles-clean.timer +systemctl --global disable systemd-tmpfiles-clean.timer