From 5247fe0667da22576328885b95385c5e7c7ab408 Mon Sep 17 00:00:00 2001 From: trdoyle Date: Fri, 14 Aug 2026 14:37:07 +0100 Subject: [PATCH 1/8] GITOPS-10535: add unit tests for core string and URL utilities Signed-off-by: trdoyle --- __mocks__/patternfly-react-core.tsx | 29 ++++++-- .../ActionDropDown/ActionDropDown.test.tsx | 6 +- src/gitops/utils/stringHelpers.test.ts | 61 ++++++++++++++-- src/gitops/utils/urls.test.ts | 73 +++++++++++++++++-- src/gitops/utils/urls.ts | 3 +- tsconfig.json | 3 + 6 files changed, 155 insertions(+), 20 deletions(-) diff --git a/__mocks__/patternfly-react-core.tsx b/__mocks__/patternfly-react-core.tsx index 17da0beab..2aaa10ea7 100644 --- a/__mocks__/patternfly-react-core.tsx +++ b/__mocks__/patternfly-react-core.tsx @@ -12,15 +12,27 @@ export const Popover: React.FC = ({ headerContent, bodyContent, children }) ); -export const MenuToggle = React.forwardRef(({ children, variant, ...rest }, ref) => ( - -)); +export const MenuToggle = React.forwardRef( + ({ children, variant, isExpanded, ...rest }, ref) => ( + + ), +); MenuToggle.displayName = 'MenuToggle'; export type MenuToggleElement = HTMLButtonElement; export type MenuToggleProps = any; -export const Dropdown: React.FC = ({ children, isOpen, toggle, ...props }) => ( +export const Dropdown: React.FC = ({ + children, + isOpen, + toggle, + //patternfly-only props — keep off the dom to avoid react warnings in tests + popperProps: _popperProps, + onOpenChange: _onOpenChange, + ...props +}) => (
{typeof toggle === 'function' ? toggle(null) : toggle} {isOpen && children} @@ -30,7 +42,14 @@ export const Dropdown: React.FC = ({ children, isOpen, toggle, ...props }) export const DropdownList: React.FC = ({ children }) =>
    {children}
; export const DropdownItem: React.FC = ({ children, description, isDisabled, ...props }) => ( -
  • {children}{description && {description}}
  • +
  • + {children} + {description && {description}} +
  • +); + +export const Divider: React.FC = ({ component: Component = 'hr', ...props }) => ( + ); export const Tooltip: React.FC = ({ content, children }) => ( diff --git a/src/gitops/utils/components/ActionDropDown/ActionDropDown.test.tsx b/src/gitops/utils/components/ActionDropDown/ActionDropDown.test.tsx index 4f719ed1f..1875713e0 100644 --- a/src/gitops/utils/components/ActionDropDown/ActionDropDown.test.tsx +++ b/src/gitops/utils/components/ActionDropDown/ActionDropDown.test.tsx @@ -15,7 +15,7 @@ describe('ActionsDropdown', () => { />, ), ).toMatchInlineSnapshot( - `"
    "`, + `"
    "`, ); }); @@ -28,13 +28,13 @@ describe('ActionsDropdown', () => { />, ), ).toMatchInlineSnapshot( - `"
    "`, + `"
    "`, ); }); it('renders with no actions', () => { expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"
    "`, + `"
    "`, ); }); }); diff --git a/src/gitops/utils/stringHelpers.test.ts b/src/gitops/utils/stringHelpers.test.ts index d1c4dbfbf..37ffb6cf5 100644 --- a/src/gitops/utils/stringHelpers.test.ts +++ b/src/gitops/utils/stringHelpers.test.ts @@ -1,23 +1,74 @@ import { detectGitType, gitUrlRegex } from './stringHelpers'; describe('gitUrlRegex', () => { - it('matches valid git URLs', () => { + it('matches valid https and git URLs', () => { expect(gitUrlRegex.test('https://github.com/foo/bar')).toMatchInlineSnapshot(`true`); expect(gitUrlRegex.test('https://github.com/foo/bar.git')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('https://www.github.com/foo/bar')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('http://github.com/foo/bar')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('git://github.com/foo/bar.git')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('https://gitlab.com/group/sub/project.git')).toMatchInlineSnapshot( + `true`, + ); + }); + + it('matches valid ssh and scp-style URLs', () => { expect(gitUrlRegex.test('git@github.com:foo/bar.git')).toMatchInlineSnapshot(`true`); expect(gitUrlRegex.test('ssh://git@github.com/foo/bar')).toMatchInlineSnapshot(`true`); - expect(gitUrlRegex.test('not a url')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test('ssh://git@gitlab.com/foo/bar.git')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('git@bitbucket.org:team/repo.git')).toMatchInlineSnapshot(`true`); + }); + + it('rejects empty, blank, and malformed URLs', () => { expect(gitUrlRegex.test('')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test(' ')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test('not a url')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test('not-a-url')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test('https://')).toMatchInlineSnapshot(`false`); + expect(gitUrlRegex.test('ftp://github.com/foo/bar')).toMatchInlineSnapshot(`false`); + }); + + it('matches non-standard but syntactically valid git hosts', () => { + expect(gitUrlRegex.test('https://gitea.example.com/foo/bar.git')).toMatchInlineSnapshot(`true`); + expect(gitUrlRegex.test('https://github.enterprise.example.com/foo/bar')).toMatchInlineSnapshot( + `true`, + ); + //host alone is still considered a url shape by this regex + expect(gitUrlRegex.test('https://github.com')).toMatchInlineSnapshot(`true`); }); }); describe('detectGitType', () => { - it('detects git providers', () => { + it('detects known providers from https URLs', () => { expect(detectGitType('https://github.com/foo/bar')).toMatchInlineSnapshot(`"github"`); + expect(detectGitType('https://www.github.com/foo/bar')).toMatchInlineSnapshot(`"github"`); expect(detectGitType('https://gitlab.com/foo/bar')).toMatchInlineSnapshot(`"gitlab"`); + expect(detectGitType('https://www.gitlab.com/foo/bar')).toMatchInlineSnapshot(`"gitlab"`); expect(detectGitType('https://bitbucket.org/foo/bar')).toMatchInlineSnapshot(`"bitbucket"`); - expect(detectGitType('https://example.com/foo/bar')).toMatchInlineSnapshot(`"other"`); - expect(detectGitType('not a url')).toMatchInlineSnapshot(`""`); + expect(detectGitType('https://www.bitbucket.org/foo/bar')).toMatchInlineSnapshot(`"bitbucket"`); + }); + + it('detects known providers from scp-style SSH URLs', () => { expect(detectGitType('git@github.com:foo/bar.git')).toMatchInlineSnapshot(`"github"`); + expect(detectGitType('git@gitlab.com:foo/bar.git')).toMatchInlineSnapshot(`"gitlab"`); + expect(detectGitType('git@bitbucket.org:team/repo.git')).toMatchInlineSnapshot(`"bitbucket"`); + }); + + it('returns empty string for invalid or empty input', () => { + expect(detectGitType('')).toMatchInlineSnapshot(`""`); + expect(detectGitType('not a url')).toMatchInlineSnapshot(`""`); + expect(detectGitType('https://')).toMatchInlineSnapshot(`""`); + }); + + it('returns other for unrecognized or non-standard formats', () => { + //valid git url shape, but not a known public provider + expect(detectGitType('https://example.com/foo/bar')).toMatchInlineSnapshot(`"other"`); + expect(detectGitType('https://gitea.example.com/foo/bar.git')).toMatchInlineSnapshot(`"other"`); + expect(detectGitType('https://github.enterprise.example.com/foo/bar')).toMatchInlineSnapshot( + `"other"`, + ); + //http (not https) and ssh:// do not match hasDomain checks, so provider is unsure + expect(detectGitType('http://github.com/foo/bar')).toMatchInlineSnapshot(`"other"`); + expect(detectGitType('ssh://git@github.com/foo/bar')).toMatchInlineSnapshot(`"other"`); }); }); diff --git a/src/gitops/utils/urls.test.ts b/src/gitops/utils/urls.test.ts index 3ed87a5e9..f185c2ca4 100644 --- a/src/gitops/utils/urls.test.ts +++ b/src/gitops/utils/urls.test.ts @@ -1,18 +1,44 @@ import { isSHA, repoUrl, revisionUrl } from './urls'; describe('isSHA', () => { - it('identifies SHA hashes', () => { + it('identifies short and full hex SHAs', () => { + expect(isSHA('abcde')).toMatchInlineSnapshot(`true`); expect(isSHA('abc123def')).toMatchInlineSnapshot(`true`); expect(isSHA('abc123def456789012345678901234567890abcd')).toMatchInlineSnapshot(`true`); + expect(isSHA('1234567890123456789012345678901234567890')).toMatchInlineSnapshot(`true`); + }); + + it('identifies sha256-prefixed hashes', () => { + expect(isSHA('sha256:abc123de')).toMatchInlineSnapshot(`true`); expect(isSHA('sha256:abc123def456789012345678901234567890abcd')).toMatchInlineSnapshot(`true`); + }); + + it('rejects empty strings, branches, tags, and missing SHAs', () => { + expect(isSHA('')).toMatchInlineSnapshot(`false`); + expect(isSHA('HEAD')).toMatchInlineSnapshot(`false`); expect(isSHA('main')).toMatchInlineSnapshot(`false`); + expect(isSHA('develop')).toMatchInlineSnapshot(`false`); expect(isSHA('v1.0.0')).toMatchInlineSnapshot(`false`); + expect(isSHA('v1.2.3')).toMatchInlineSnapshot(`false`); + }); + + it('rejects values outside the supported hex length and charset', () => { + //too short for plain sha (needs 5–40 hex chars) expect(isSHA('abc')).toMatchInlineSnapshot(`false`); + expect(isSHA('abcd')).toMatchInlineSnapshot(`false`); + //too long for plain sha (>40) + expect(isSHA('12345678901234567890123456789012345678901')).toMatchInlineSnapshot(`false`); + //uppercase is not matched by the lowercase-only regex + expect(isSHA('ABCDEF')).toMatchInlineSnapshot(`false`); + expect(isSHA('abc123DEF')).toMatchInlineSnapshot(`false`); + //sha256 prefix with empty or too-short hash + expect(isSHA('sha256:')).toMatchInlineSnapshot(`false`); + expect(isSHA('sha256:abc')).toMatchInlineSnapshot(`false`); }); }); describe('repoUrl', () => { - it('extracts repo URLs from various formats', () => { + it('extracts canonical https repo paths from common formats', () => { expect(repoUrl('https://github.com/argoproj/argo-cd.git')).toMatchInlineSnapshot( `"https://github.com/argoproj/argo-cd"`, ); @@ -22,24 +48,30 @@ describe('repoUrl', () => { expect(repoUrl('git@github.com:argoproj/argo-cd.git')).toMatchInlineSnapshot( `"https://github.com/argoproj/argo-cd"`, ); + expect(repoUrl('ssh://git@github.com/foo/bar.git')).toMatchInlineSnapshot( + `"https://github.com/foo/bar"`, + ); expect(repoUrl('https://gitlab.com/group/project.git')).toMatchInlineSnapshot( `"https://gitlab.com/group/project"`, ); expect(repoUrl('https://bitbucket.org/team/repo.git')).toMatchInlineSnapshot( `"https://bitbucket.org/team/repo"`, ); + }); + + it('returns null for empty, malformed, or unsupported providers', () => { + expect(repoUrl('')).toMatchInlineSnapshot(`null`); + expect(repoUrl('not a url')).toMatchInlineSnapshot(`null`); expect(repoUrl('https://internal.example.com/repo.git')).toMatchInlineSnapshot(`null`); + expect(repoUrl('https://gitea.io/foo/bar')).toMatchInlineSnapshot(`null`); }); }); describe('revisionUrl', () => { - it('builds revision URLs for different providers', () => { + it('builds commit URLs for SHA revisions', () => { expect(revisionUrl('https://github.com/foo/bar.git', 'abc123def', false)).toMatchInlineSnapshot( `"https://github.com/foo/bar/commit/abc123def"`, ); - expect(revisionUrl('https://github.com/foo/bar.git', 'main', false)).toMatchInlineSnapshot( - `"https://github.com/foo/bar/tree/main"`, - ); expect(revisionUrl('https://gitlab.com/foo/bar.git', 'abc123def', false)).toMatchInlineSnapshot( `"https://gitlab.com/foo/bar/-/commit/abc123def"`, ); @@ -49,8 +81,37 @@ describe('revisionUrl', () => { expect( revisionUrl('https://bitbucket.org/foo/bar.git', 'abc123def', true), ).toMatchInlineSnapshot(`"https://bitbucket.org/foo/bar/src/abc123def"`); + }); + + it('builds tree/src URLs for branch names', () => { + expect(revisionUrl('https://github.com/foo/bar.git', 'main', false)).toMatchInlineSnapshot( + `"https://github.com/foo/bar/tree/main"`, + ); + expect(revisionUrl('https://gitlab.com/foo/bar.git', 'main', false)).toMatchInlineSnapshot( + `"https://gitlab.com/foo/bar/-/tree/main"`, + ); + expect(revisionUrl('https://bitbucket.org/foo/bar.git', 'main', false)).toMatchInlineSnapshot( + `"https://bitbucket.org/foo/bar/src/main"`, + ); + expect(revisionUrl('https://bitbucket.org/foo/bar.git', 'main', true)).toMatchInlineSnapshot( + `"https://bitbucket.org/foo/bar/src/main"`, + ); + }); + + it('defaults missing revision to HEAD', () => { expect(revisionUrl('https://github.com/foo/bar.git', '', false)).toMatchInlineSnapshot( `"https://github.com/foo/bar/tree/HEAD"`, ); + expect(revisionUrl('https://github.com/foo/bar.git', null as any, false)).toMatchInlineSnapshot( + `"https://github.com/foo/bar/tree/HEAD"`, + ); + }); + + it('returns null for empty, malformed, or unsupported repo URLs', () => { + expect(revisionUrl('', 'abc123', false)).toMatchInlineSnapshot(`null`); + expect(revisionUrl('not a url', 'abc123', false)).toMatchInlineSnapshot(`null`); + expect(revisionUrl('https://gitea.io/foo/bar.git', 'abc123', false)).toMatchInlineSnapshot( + `null`, + ); }); }); diff --git a/src/gitops/utils/urls.ts b/src/gitops/utils/urls.ts index 4a3e89869..b5c0b08a9 100644 --- a/src/gitops/utils/urls.ts +++ b/src/gitops/utils/urls.ts @@ -3,7 +3,8 @@ * https://github.com/argoproj/argo-cd/blob/4bd8b07c514e26c6b7837f30d52afd1a3cdedcfd/ui/src/app/shared/components/urls.ts */ -import * as GitUrlParse from 'git-url-parse'; +//cjs package — default import needs esmoduleinterop or jest can't call it +import GitUrlParse from 'git-url-parse'; import { GitUrl } from 'git-url-parse'; export const isSHA = (revision: string) => { diff --git a/tsconfig.json b/tsconfig.json index ec38955f2..8a117746e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,11 @@ "allowJs": true, "strict": false, "allowSyntheticDefaultImports": true, + //so cjs default imports (git-url-parse) work in jest + "esModuleInterop": true, "noUnusedLocals": true, "lib": ["dom", "es2017"], + "types": ["jest"], "paths": { "@gitops/*": ["src/gitops/*"], "@gitops-models/*": ["src/gitops/models/*"], From 5b5283e022d15a8456683b4095cf77a4e66fc1dc Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Tue, 18 Aug 2026 00:58:02 -0400 Subject: [PATCH 2/8] Add Labels column to App, AppSet, ImageUpdater list pages (#10541) Signed-off-by: Keith Chong --- .../imageupdater/ImageUpdaterList.tsx | 42 +++++++++++++++++-- src/gitops/components/project/ProjectList.tsx | 10 ++--- src/gitops/components/rollout/RolloutList.tsx | 7 +++- .../components/shared/ApplicationList.tsx | 36 +++++++++++++++- .../components/shared/ApplicationSetList.tsx | 37 +++++++++++++++- .../shared/MetadataLabels/MetadataLabels.tsx | 6 ++- 6 files changed, 122 insertions(+), 16 deletions(-) diff --git a/src/gitops/components/imageupdater/ImageUpdaterList.tsx b/src/gitops/components/imageupdater/ImageUpdaterList.tsx index 9a183b0d2..2ea18ce78 100644 --- a/src/gitops/components/imageupdater/ImageUpdaterList.tsx +++ b/src/gitops/components/imageupdater/ImageUpdaterList.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom-v5-compat'; import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; +import * as YamlFormatter from 'yaml'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; import { modelToGroupVersionKind } from '@gitops/utils/utils'; @@ -34,6 +35,7 @@ import { useShowOperandsInAllNamespaces, } from '../shared/AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import MetadataLabels from '../shared/MetadataLabels'; import { useImageUpdaterActionsProvider } from './hooks/useImageUpdaterActionsProvider'; @@ -71,6 +73,7 @@ const ImageUpdaterList: React.FC = ({ 'images', 'last-checked', 'ready', + 'labels', 'actions', ].map((key) => ({ key })); }, [showNamespaceColumn]); @@ -251,6 +254,10 @@ export const sortData = ( aValue = a.status?.conditions?.find((c) => c.type === 'Ready')?.status || ''; bValue = b.status?.conditions?.find((c) => c.type === 'Ready')?.status || ''; break; + case 'labels': + aValue = YamlFormatter.stringify(a.metadata?.labels || {}); + bValue = YamlFormatter.stringify(b.metadata?.labels || {}); + break; default: return 0; } @@ -277,7 +284,7 @@ export const useColumnsDV = ( cell: t('Name'), props: { 'aria-label': 'name', - className: 'pf-m-width-20', + className: 'pf-m-width-30', sort: getSortParams(0), style: { minWidth: '200px' }, }, @@ -299,7 +306,7 @@ export const useColumnsDV = ( cell: t('Apps'), props: { 'aria-label': 'apps', - className: 'pf-m-width-10', + className: 'pf-m-width-20', sort: getSortParams(1 + i), }, }, @@ -307,7 +314,7 @@ export const useColumnsDV = ( cell: t('Images'), props: { 'aria-label': 'images', - className: 'pf-m-width-10', + className: 'pf-m-width-20', sort: getSortParams(2 + i), }, }, @@ -315,7 +322,7 @@ export const useColumnsDV = ( cell: t('Last Checked'), props: { 'aria-label': 'last checked', - className: 'pf-m-width-15', + className: 'pf-m-width-20', sort: getSortParams(3 + i), }, }, @@ -327,6 +334,14 @@ export const useColumnsDV = ( sort: getSortParams(4 + i), }, }, + { + cell: t('Labels'), + props: { + 'aria-label': 'labels', + className: 'pf-m-width-10', + sort: getSortParams(5 + i), + }, + }, { cell: '', props: { 'aria-label': 'actions' }, @@ -400,6 +415,25 @@ export const useImageUpdaterRowsDV = ( cell: readyCondition ? String(isReady) : '-', dataLabel: 'Ready', }, + { + id: 'labels', + dataLabel: 'Labels', + cell: ( +
    + +
    + ), + }, { id: 'actions-' + index, cell: , diff --git a/src/gitops/components/project/ProjectList.tsx b/src/gitops/components/project/ProjectList.tsx index 3eddd7d6f..9f5432702 100644 --- a/src/gitops/components/project/ProjectList.tsx +++ b/src/gitops/components/project/ProjectList.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom-v5-compat'; import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; +import * as YamlFormatter from 'yaml'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; import { modelToGroupVersionKind, modelToRef } from '@gitops/utils/utils'; @@ -360,8 +361,8 @@ export const sortData = ( bValue = getApplicationsCount(b, applications, appsLoaded); break; case 'labels': - aValue = a.metadata?.labels || {}; - bValue = b.metadata?.labels || {}; + aValue = YamlFormatter.stringify(a.metadata?.labels || {}); + bValue = YamlFormatter.stringify(b.metadata?.labels || {}); break; case 'last-updated': aValue = getLastUpdateTimestamp(a) || ''; @@ -422,10 +423,7 @@ export const useColumnsDV = ( }, { cell: t('Labels'), - props: { - 'aria-label': 'labels', - className: 'pf-m-width-20', - }, + props: sortableHeaderProps('labels', 'pf-m-width-20', getSortParams(3 + i)), }, { cell: t('Last Updated'), diff --git a/src/gitops/components/rollout/RolloutList.tsx b/src/gitops/components/rollout/RolloutList.tsx index e4375bdc0..714379b08 100644 --- a/src/gitops/components/rollout/RolloutList.tsx +++ b/src/gitops/components/rollout/RolloutList.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Link } from 'react-router-dom-v5-compat'; import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; +import * as YamlFormatter from 'yaml'; import { AppProjectKind } from '@gitops/models/AppProjectModel'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; @@ -250,8 +251,8 @@ export const sortData = ( bValue = b.status?.readyReplicas || ''; break; case 'labels': - aValue = a.metadata?.labels || ''; - bValue = b.metadata?.labels || ''; + aValue = YamlFormatter.stringify(a.metadata?.labels || {}); + bValue = YamlFormatter.stringify(b.metadata?.labels || {}); break; case 'selector': aValue = a.status?.selector || ''; @@ -323,6 +324,7 @@ export const useColumnsDV = ( props: { 'aria-label': 'labels', className: 'pf-m-width-15', + sort: getSortParams(3 + i), }, }, { @@ -415,6 +417,7 @@ export const useRolloutsRowsDV = ( }, { id: 'labels', + dataLabel: 'Labels', cell: (
    = ({ 'sync-status', 'health-status', 'revision', + 'labels', 'project', 'actions', ].map((key) => ({ key })), @@ -317,6 +320,10 @@ export const sortData = ( aValue = a.status?.sync?.revision || ''; bValue = b.status?.sync?.revision || ''; break; + case 'labels': + aValue = YamlFormatter.stringify(a.metadata?.labels || {}); + bValue = YamlFormatter.stringify(b.metadata?.labels || {}); + break; case 'project': aValue = a.spec?.project || ''; bValue = b.spec?.project || ''; @@ -431,6 +438,25 @@ const useApplicationRowsDV = (applicationsList, namespace): DataViewTr[] => { ), }, + { + id: 'labels', + dataLabel: 'Labels', + cell: ( +
    + +
    + ), + }, { id: app.spec?.project, cell: app.spec?.project && ( @@ -506,12 +532,20 @@ const useColumnsDV = ( sort: getSortParams(3 + i), }, }, + { + cell: t('Labels'), + props: { + 'aria-label': 'labels', + className: 'pf-m-width-20', + sort: getSortParams(4 + i), + }, + }, { cell: t('App Project'), props: { 'aria-label': 'project', className: 'pf-m-width-20', - sort: getSortParams(4 + i), + sort: getSortParams(5 + i), }, }, { diff --git a/src/gitops/components/shared/ApplicationSetList.tsx b/src/gitops/components/shared/ApplicationSetList.tsx index ae4cc9341..704e760e5 100644 --- a/src/gitops/components/shared/ApplicationSetList.tsx +++ b/src/gitops/components/shared/ApplicationSetList.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; +import * as YamlFormatter from 'yaml'; import { K8sResourceCommon, @@ -38,6 +39,7 @@ import { useShowOperandsInAllNamespaces, } from './AllNamespaces'; import { GitOpsDataViewTable, useGitOpsDataViewSort } from './DataView'; +import MetadataLabels from './MetadataLabels'; const formatCreationTimestamp = (timestamp: string): string => { if (!timestamp) return '-'; @@ -147,6 +149,7 @@ const ApplicationSetList: React.FC = ({ 'status', 'generated-apps', 'generators', + 'labels', 'created-at', 'actions', ].map((key) => ({ key })), @@ -362,6 +365,25 @@ const useApplicationSetRowsDV = ( id: 'generators-' + index, cell:
    {getAppSetGeneratorCount(appSet).toString()}
    , }, + { + id: 'labels', + dataLabel: 'Labels', + cell: ( +
    + +
    + ), + }, { id: 'created-at-' + index, cell:
    {formatCreationTimestamp(appSet.metadata.creationTimestamp)}
    , @@ -427,12 +449,20 @@ const useColumnsDV = ( sort: getSortParams(3 + i), }, }, + { + cell: t('Labels'), + props: { + 'aria-label': 'labels', + className: 'pf-m-width-20', + sort: getSortParams(4 + i), + }, + }, { cell: t('Created At'), props: { 'aria-label': 'created at', className: 'pf-m-width-15', - sort: getSortParams(4 + i), + sort: getSortParams(5 + i), }, }, { @@ -492,11 +522,14 @@ export const sortData = ( aValue = getGeneratedAppsCount(a, applications, appsLoaded); bValue = getGeneratedAppsCount(b, applications, appsLoaded); break; - case 'generators': aValue = getAppSetGeneratorCount(a); bValue = getAppSetGeneratorCount(b); break; + case 'labels': + aValue = YamlFormatter.stringify(a.metadata?.labels || {}); + bValue = YamlFormatter.stringify(b.metadata?.labels || {}); + break; case 'created-at': aValue = new Date(a.metadata?.creationTimestamp || 0).getTime(); bValue = new Date(b.metadata?.creationTimestamp || 0).getTime(); diff --git a/src/gitops/components/shared/MetadataLabels/MetadataLabels.tsx b/src/gitops/components/shared/MetadataLabels/MetadataLabels.tsx index 183c717a2..00c2aec42 100644 --- a/src/gitops/components/shared/MetadataLabels/MetadataLabels.tsx +++ b/src/gitops/components/shared/MetadataLabels/MetadataLabels.tsx @@ -41,7 +41,11 @@ type MetadataLabelsProps = { export const MetadataLabels: React.FC = ({ kind, labels, numLabels = 10 }) => { const { t } = useGitOpsTranslation(); return labels && Object.keys(labels).length > 0 ? ( - + {Object.keys(labels || {})?.map((key) => { return ( From c186f7ddad68e88cd4912a85b79bfc3f47c6ea49 Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Tue, 18 Aug 2026 10:17:36 -0400 Subject: [PATCH 3/8] Remove Tech Preview Badge and related strings Signed-off-by: Keith Chong --- locales/en/plugin__gitops-plugin.json | 8 ++---- locales/en/plugin__gitops-public.json | 1 - locales/ja/plugin__gitops-plugin.json | 8 ++---- locales/ja/plugin__gitops-public.json | 1 - locales/ko/plugin__gitops-plugin.json | 8 ++---- locales/ko/plugin__gitops-public.json | 1 - locales/zh/plugin__gitops-plugin.json | 8 ++---- locales/zh/plugin__gitops-public.json | 1 - .../imageupdater/ImageUpdaterList.tsx | 10 -------- src/gitops/components/project/ProjectList.tsx | 10 -------- src/gitops/components/rollout/RolloutList.tsx | 10 -------- .../components/shared/ApplicationList.tsx | 10 -------- .../components/shared/ApplicationSetList.tsx | 10 -------- .../DetailsPageHeader/DetailsPageHeader.tsx | 11 -------- .../sidebar/DeploymentSideBarDetails.tsx | 6 ----- .../topology/sidebar/resource-sections.tsx | 9 +------ src/plugin/import/badges/Badge.scss | 8 ------ .../import/badges/TechPreviewBadge.test.tsx | 18 ------------- src/plugin/import/badges/TechPreviewBadge.tsx | 25 ------------------- 19 files changed, 9 insertions(+), 154 deletions(-) delete mode 100644 src/plugin/import/badges/Badge.scss delete mode 100644 src/plugin/import/badges/TechPreviewBadge.test.tsx delete mode 100644 src/plugin/import/badges/TechPreviewBadge.tsx diff --git a/locales/en/plugin__gitops-plugin.json b/locales/en/plugin__gitops-plugin.json index ea77897e5..cfd115c75 100644 --- a/locales/en/plugin__gitops-plugin.json +++ b/locales/en/plugin__gitops-plugin.json @@ -141,11 +141,11 @@ "Unable to load data": "Unable to load data", "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", "ImageUpdaters": "ImageUpdaters", - "This list page is under tech preview, but not necessarily the resources it represents": "This list page is under tech preview, but not necessarily the resources it represents", "Create ImageUpdater": "Create ImageUpdater", "Apps": "Apps", "Images": "Images", "Last Checked": "Last Checked", + "Labels": "Labels", "Has Apps": "Has Apps", "No Apps": "No Apps", "Not Ready": "Not Ready", @@ -218,7 +218,6 @@ "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", "AppProjects": "AppProjects", "Create AppProject": "Create AppProject", - "Labels": "Labels", "Last Updated": "Last Updated", "Has Description": "Has Description", "No Description": "No Description", @@ -343,18 +342,15 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "This details page is under tech preview, but not necessarily the resource it represents": "This details page is under tech preview, but not necessarily the resource it represents", "List view": "List view", "Graph view": "Graph view", "Sync": "Sync", "Stop": "Stop", "Refresh": "Refresh", "Refresh (Hard)": "Refresh (Hard)", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Actions": "Actions", "You don't have permission to perform this action": "You don't have permission to perform this action", "annotations": "annotations", "annotation": "annotation", - "No owner": "No owner", - "Tech preview": "Tech preview" + "No owner": "No owner" } diff --git a/locales/en/plugin__gitops-public.json b/locales/en/plugin__gitops-public.json index b0176b468..f0284a431 100644 --- a/locales/en/plugin__gitops-public.json +++ b/locales/en/plugin__gitops-public.json @@ -5,7 +5,6 @@ "View logs": "View logs", "Open URL": "Open URL", "Edit": "Edit", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Rollout": "Rollout", "Name": "Name", "Namespace": "Namespace", diff --git a/locales/ja/plugin__gitops-plugin.json b/locales/ja/plugin__gitops-plugin.json index 52e937fa2..f77e16ac2 100644 --- a/locales/ja/plugin__gitops-plugin.json +++ b/locales/ja/plugin__gitops-plugin.json @@ -141,11 +141,11 @@ "Unable to load data": "Unable to load data", "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", "ImageUpdaters": "ImageUpdaters", - "This list page is under tech preview, but not necessarily the resources it represents": "This list page is under tech preview, but not necessarily the resources it represents", "Create ImageUpdater": "Create ImageUpdater", "Apps": "Apps", "Images": "Images", "Last Checked": "Last Checked", + "Labels": "Labels", "Has Apps": "Has Apps", "No Apps": "No Apps", "Not Ready": "Not Ready", @@ -218,7 +218,6 @@ "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", "AppProjects": "AppProjects", "Create AppProject": "Create AppProject", - "Labels": "Labels", "Last Updated": "Last Updated", "Has Description": "Has Description", "No Description": "No Description", @@ -343,18 +342,15 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "This details page is under tech preview, but not necessarily the resource it represents": "This details page is under tech preview, but not necessarily the resource it represents", "List view": "List view", "Graph view": "Graph view", "Sync": "Sync", "Stop": "Stop", "Refresh": "Refresh", "Refresh (Hard)": "Refresh (Hard)", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Actions": "Actions", "You don't have permission to perform this action": "You don't have permission to perform this action", "annotations": "annotations", "annotation": "annotation", - "No owner": "No owner", - "Tech preview": "Tech preview" + "No owner": "No owner" } diff --git a/locales/ja/plugin__gitops-public.json b/locales/ja/plugin__gitops-public.json index b0176b468..f0284a431 100644 --- a/locales/ja/plugin__gitops-public.json +++ b/locales/ja/plugin__gitops-public.json @@ -5,7 +5,6 @@ "View logs": "View logs", "Open URL": "Open URL", "Edit": "Edit", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Rollout": "Rollout", "Name": "Name", "Namespace": "Namespace", diff --git a/locales/ko/plugin__gitops-plugin.json b/locales/ko/plugin__gitops-plugin.json index 72ff91288..76b66c62e 100644 --- a/locales/ko/plugin__gitops-plugin.json +++ b/locales/ko/plugin__gitops-plugin.json @@ -141,11 +141,11 @@ "Unable to load data": "Unable to load data", "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", "ImageUpdaters": "ImageUpdaters", - "This list page is under tech preview, but not necessarily the resources it represents": "This list page is under tech preview, but not necessarily the resources it represents", "Create ImageUpdater": "Create ImageUpdater", "Apps": "Apps", "Images": "Images", "Last Checked": "Last Checked", + "Labels": "Labels", "Has Apps": "Has Apps", "No Apps": "No Apps", "Not Ready": "Not Ready", @@ -218,7 +218,6 @@ "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", "AppProjects": "AppProjects", "Create AppProject": "Create AppProject", - "Labels": "Labels", "Last Updated": "Last Updated", "Has Description": "Has Description", "No Description": "No Description", @@ -343,18 +342,15 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "This details page is under tech preview, but not necessarily the resource it represents": "This details page is under tech preview, but not necessarily the resource it represents", "List view": "List view", "Graph view": "Graph view", "Sync": "Sync", "Stop": "Stop", "Refresh": "Refresh", "Refresh (Hard)": "Refresh (Hard)", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Actions": "Actions", "You don't have permission to perform this action": "You don't have permission to perform this action", "annotations": "annotations", "annotation": "annotation", - "No owner": "No owner", - "Tech preview": "Tech preview" + "No owner": "No owner" } diff --git a/locales/ko/plugin__gitops-public.json b/locales/ko/plugin__gitops-public.json index b0176b468..f0284a431 100644 --- a/locales/ko/plugin__gitops-public.json +++ b/locales/ko/plugin__gitops-public.json @@ -5,7 +5,6 @@ "View logs": "View logs", "Open URL": "Open URL", "Edit": "Edit", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Rollout": "Rollout", "Name": "Name", "Namespace": "Namespace", diff --git a/locales/zh/plugin__gitops-plugin.json b/locales/zh/plugin__gitops-plugin.json index cb6943ef7..d016eedc6 100644 --- a/locales/zh/plugin__gitops-plugin.json +++ b/locales/zh/plugin__gitops-plugin.json @@ -141,11 +141,11 @@ "Unable to load data": "Unable to load data", "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", "ImageUpdaters": "ImageUpdaters", - "This list page is under tech preview, but not necessarily the resources it represents": "This list page is under tech preview, but not necessarily the resources it represents", "Create ImageUpdater": "Create ImageUpdater", "Apps": "Apps", "Images": "Images", "Last Checked": "Last Checked", + "Labels": "Labels", "Has Apps": "Has Apps", "No Apps": "No Apps", "Not Ready": "Not Ready", @@ -218,7 +218,6 @@ "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", "AppProjects": "AppProjects", "Create AppProject": "Create AppProject", - "Labels": "Labels", "Last Updated": "Last Updated", "Has Description": "Has Description", "No Description": "No Description", @@ -343,18 +342,15 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "This details page is under tech preview, but not necessarily the resource it represents": "This details page is under tech preview, but not necessarily the resource it represents", "List view": "List view", "Graph view": "Graph view", "Sync": "Sync", "Stop": "Stop", "Refresh": "Refresh", "Refresh (Hard)": "Refresh (Hard)", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Actions": "Actions", "You don't have permission to perform this action": "You don't have permission to perform this action", "annotations": "annotations", "annotation": "annotation", - "No owner": "No owner", - "Tech preview": "Tech preview" + "No owner": "No owner" } diff --git a/locales/zh/plugin__gitops-public.json b/locales/zh/plugin__gitops-public.json index b0176b468..f0284a431 100644 --- a/locales/zh/plugin__gitops-public.json +++ b/locales/zh/plugin__gitops-public.json @@ -5,7 +5,6 @@ "View logs": "View logs", "Open URL": "Open URL", "Edit": "Edit", - "Rollouts in the Topology View is under tech preview": "Rollouts in the Topology View is under tech preview", "Rollout": "Rollout", "Name": "Name", "Namespace": "Namespace", diff --git a/src/gitops/components/imageupdater/ImageUpdaterList.tsx b/src/gitops/components/imageupdater/ImageUpdaterList.tsx index 2ea18ce78..7963211ba 100644 --- a/src/gitops/components/imageupdater/ImageUpdaterList.tsx +++ b/src/gitops/components/imageupdater/ImageUpdaterList.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom-v5-compat'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import * as YamlFormatter from 'yaml'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; @@ -174,15 +173,6 @@ const ImageUpdaterList: React.FC = ({ {showTitle == undefined && ( - ) - } helpText={ location.pathname?.includes('openshift-gitops-operator') ? ( diff --git a/src/gitops/components/project/ProjectList.tsx b/src/gitops/components/project/ProjectList.tsx index 9f5432702..0f610604c 100644 --- a/src/gitops/components/project/ProjectList.tsx +++ b/src/gitops/components/project/ProjectList.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom-v5-compat'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import * as YamlFormatter from 'yaml'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; @@ -196,15 +195,6 @@ const ProjectList: React.FC = ({ {showTitle == undefined && ( - ) - } helpText={ location.pathname?.includes('openshift-gitops-operator') ? ( diff --git a/src/gitops/components/rollout/RolloutList.tsx b/src/gitops/components/rollout/RolloutList.tsx index 714379b08..0ef0bf5c0 100644 --- a/src/gitops/components/rollout/RolloutList.tsx +++ b/src/gitops/components/rollout/RolloutList.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { Link } from 'react-router-dom-v5-compat'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import * as YamlFormatter from 'yaml'; import { AppProjectKind } from '@gitops/models/AppProjectModel'; @@ -174,15 +173,6 @@ const RolloutList: React.FC = ({ {showTitle == undefined && ( - ) - } helpText={ location.pathname?.includes('openshift-gitops-operator') ? ( diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index 06866d14b..a5b4bb2f4 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import * as YamlFormatter from 'yaml'; import { ApplicationSetKind } from '@gitops/models/ApplicationSetModel'; @@ -211,15 +210,6 @@ const ApplicationList: React.FC = ({ {showTitle == undefined && (project == undefined || appset == undefined) && ( - ) - } helpText={ location.pathname?.includes('openshift-gitops-operator') ? ( diff --git a/src/gitops/components/shared/ApplicationSetList.tsx b/src/gitops/components/shared/ApplicationSetList.tsx index 704e760e5..1663ef6af 100644 --- a/src/gitops/components/shared/ApplicationSetList.tsx +++ b/src/gitops/components/shared/ApplicationSetList.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import * as YamlFormatter from 'yaml'; import { @@ -257,15 +256,6 @@ const ApplicationSetList: React.FC = ({ {showTitle == undefined && ( - ) - } helpText={ location.pathname?.includes('openshift-gitops-operator') ? ( diff --git a/src/gitops/components/shared/DetailsPageHeader/DetailsPageHeader.tsx b/src/gitops/components/shared/DetailsPageHeader/DetailsPageHeader.tsx index e6fab9dde..8d17f17ed 100644 --- a/src/gitops/components/shared/DetailsPageHeader/DetailsPageHeader.tsx +++ b/src/gitops/components/shared/DetailsPageHeader/DetailsPageHeader.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { Link } from 'react-router-dom-v5-compat'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import FavoriteButton from '@gitops/components/shared/FavoriteButton/FavoriteButton'; import ActionsDropdown from '@gitops/utils/components/ActionDropDown/ActionDropDown'; @@ -99,16 +98,6 @@ const DetailsPageHeader: React.FC = ({ {name ?? obj?.metadata?.name}{' '} {isApplicationRefreshing(obj) ? : } - - - diff --git a/src/gitops/topology/sidebar/DeploymentSideBarDetails.tsx b/src/gitops/topology/sidebar/DeploymentSideBarDetails.tsx index 6b6b0bf3e..e5c05f4d7 100644 --- a/src/gitops/topology/sidebar/DeploymentSideBarDetails.tsx +++ b/src/gitops/topology/sidebar/DeploymentSideBarDetails.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; import classNames from 'classnames'; import * as _ from 'lodash'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; import { DetailsTabSectionExtensionHook, @@ -242,11 +241,6 @@ export const DeploymentSideBarDetails: React.FC = <>
    -
    diff --git a/src/gitops/topology/sidebar/resource-sections.tsx b/src/gitops/topology/sidebar/resource-sections.tsx index 0170455ef..dd5f3a890 100644 --- a/src/gitops/topology/sidebar/resource-sections.tsx +++ b/src/gitops/topology/sidebar/resource-sections.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; -import TechPreviewBadge from 'src/plugin/import/badges/TechPreviewBadge'; -import { t } from '@gitops/utils/hooks/useGitOpsTranslation'; import { DetailsTabSectionExtensionHook, K8sResourceKind, @@ -61,12 +59,7 @@ export const ResourceSection: React.FC<{ return (
    - - - - +
    {statusOfPods && statusOfPods.pods && (
    diff --git a/src/plugin/import/badges/Badge.scss b/src/plugin/import/badges/Badge.scss deleted file mode 100644 index b53c09ba9..000000000 --- a/src/plugin/import/badges/Badge.scss +++ /dev/null @@ -1,8 +0,0 @@ -.gitops-plugin__preview-badge { - &.pf-v6-c-label { - --pf-v6-c-label--BackgroundColor: #d93f00; - --pf-v6-c-label--Color: var(--pf-t--color--white); - margin-top: 3px; - padding-bottom: 7px; - } -} diff --git a/src/plugin/import/badges/TechPreviewBadge.test.tsx b/src/plugin/import/badges/TechPreviewBadge.test.tsx deleted file mode 100644 index b3e6576c1..000000000 --- a/src/plugin/import/badges/TechPreviewBadge.test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { renderToStaticMarkup } from 'react-dom/server'; -import TechPreviewBadge from './TechPreviewBadge'; - -describe('TechPreviewBadge', () => { - it('renders label without tooltip', () => { - expect(renderToStaticMarkup()).toMatchInlineSnapshot( - `"plugin__gitops-plugin~Tech preview"`, - ); - }); - - it('renders with tooltip when tooltipContent provided', () => { - expect( - renderToStaticMarkup(), - ).toMatchInlineSnapshot( - `"plugin__gitops-plugin~Tech preview"`, - ); - }); -}); diff --git a/src/plugin/import/badges/TechPreviewBadge.tsx b/src/plugin/import/badges/TechPreviewBadge.tsx deleted file mode 100644 index ee406eb59..000000000 --- a/src/plugin/import/badges/TechPreviewBadge.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import * as React from 'react'; -import { TFunction, useTranslation } from 'react-i18next'; - -import { Label, Tooltip } from '@patternfly/react-core'; - -import './Badge.scss'; - -const getBadgeLabel = (t: TFunction) => { - return ( - - ); -}; - -const TechPreviewBadge: React.FC<{ tooltipContent?: string }> = ({ tooltipContent }) => { - const { t } = useTranslation('plugin__gitops-plugin'); - return tooltipContent ? ( - {getBadgeLabel(t)} - ) : ( - getBadgeLabel(t) - ); -}; - -export default TechPreviewBadge; From b89024223fe58c93f4e031b29bb944a90a7d6679 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 18 Aug 2026 12:40:42 -0400 Subject: [PATCH 4/8] feat: add pagination to list pages Signed-off-by: Atif Ali --- locales/en/plugin__gitops-plugin.json | 10 +- locales/ja/plugin__gitops-plugin.json | 10 +- locales/ko/plugin__gitops-plugin.json | 10 +- locales/zh/plugin__gitops-plugin.json | 10 +- .../components/shared/ApplicationList.tsx | 28 +++- .../shared/ApplicationSetApplicationsView.tsx | 8 +- .../shared/DataView/GitOpsDataViewTable.tsx | 154 +++++++++++++++++- .../DataView/gitOpsDataViewPagination.test.ts | 44 +++++ .../DataView/gitOpsDataViewPagination.ts | 30 ++++ .../components/shared/DataView/index.ts | 8 + 10 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts create mode 100644 src/gitops/components/shared/DataView/gitOpsDataViewPagination.ts diff --git a/locales/en/plugin__gitops-plugin.json b/locales/en/plugin__gitops-plugin.json index ea77897e5..dde474b4e 100644 --- a/locales/en/plugin__gitops-plugin.json +++ b/locales/en/plugin__gitops-plugin.json @@ -356,5 +356,13 @@ "annotations": "annotations", "annotation": "annotation", "No owner": "No owner", - "Tech preview": "Tech preview" + "Tech preview": "Tech preview", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of" } diff --git a/locales/ja/plugin__gitops-plugin.json b/locales/ja/plugin__gitops-plugin.json index 52e937fa2..101a6ed82 100644 --- a/locales/ja/plugin__gitops-plugin.json +++ b/locales/ja/plugin__gitops-plugin.json @@ -356,5 +356,13 @@ "annotations": "annotations", "annotation": "annotation", "No owner": "No owner", - "Tech preview": "Tech preview" + "Tech preview": "Tech preview", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of" } diff --git a/locales/ko/plugin__gitops-plugin.json b/locales/ko/plugin__gitops-plugin.json index 72ff91288..672c743f1 100644 --- a/locales/ko/plugin__gitops-plugin.json +++ b/locales/ko/plugin__gitops-plugin.json @@ -356,5 +356,13 @@ "annotations": "annotations", "annotation": "annotation", "No owner": "No owner", - "Tech preview": "Tech preview" + "Tech preview": "Tech preview", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of" } diff --git a/locales/zh/plugin__gitops-plugin.json b/locales/zh/plugin__gitops-plugin.json index cb6943ef7..513ae9cf1 100644 --- a/locales/zh/plugin__gitops-plugin.json +++ b/locales/zh/plugin__gitops-plugin.json @@ -356,5 +356,13 @@ "annotations": "annotations", "annotation": "annotation", "No owner": "No owner", - "Tech preview": "Tech preview" + "Tech preview": "Tech preview", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of" } diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index 5a1144e42..3430d815d 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -43,7 +43,13 @@ import { useShowOperandsInAllNamespaces, } from './AllNamespaces'; import ApplicationSetApplicationsView from './ApplicationSetApplicationsView'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from './DataView'; +import { + getGitOpsPaginationResetKey, + GitOpsDataViewTable, + paginateItems, + useGitOpsDataViewPagination, + useGitOpsDataViewSort, +} from './DataView'; interface ApplicationProps { namespace: string; @@ -149,7 +155,21 @@ const ApplicationList: React.FC = ({ }); }); }, [filteredData, searchQuery]); - const rows = useApplicationRowsDV(filteredBySearch, namespace); + + const searchParamsKey = searchParams.toString(); + const paginationResetKey = React.useMemo( + () => getGitOpsPaginationResetKey(namespace, new URLSearchParams(searchParamsKey)), + [namespace, searchParamsKey], + ); + const pagination = useGitOpsDataViewPagination({ + itemCount: filteredBySearch.length, + resetKey: paginationResetKey, + }); + const pagedApplications = React.useMemo( + () => paginateItems(filteredBySearch, pagination.page, pagination.perPage), + [filteredBySearch, pagination.page, pagination.perPage], + ); + const rows = useApplicationRowsDV(pagedApplications, namespace); // Check if there are applications owned by this ApplicationSet initially (before filters/search) const hasOwnedApplications = ownedApps.length > 0; @@ -269,6 +289,8 @@ const ApplicationList: React.FC = ({ emptyState={empty} errorState={error || undefined} isError={!!loadError} + itemCount={filteredBySearch.length} + pagination={pagination} /> )} {!appset && ( @@ -279,6 +301,8 @@ const ApplicationList: React.FC = ({ emptyState={empty} errorState={error || undefined} isError={!!loadError} + itemCount={filteredBySearch.length} + pagination={pagination} /> )} diff --git a/src/gitops/components/shared/ApplicationSetApplicationsView.tsx b/src/gitops/components/shared/ApplicationSetApplicationsView.tsx index 2ff53f875..367aa5f1a 100644 --- a/src/gitops/components/shared/ApplicationSetApplicationsView.tsx +++ b/src/gitops/components/shared/ApplicationSetApplicationsView.tsx @@ -9,7 +9,7 @@ import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/Dat import { ApplicationSetGraphView } from '../appset/graph/ApplicationSetGraphView'; -import { GitOpsDataViewTable } from './DataView'; +import { type GitOpsDataViewPagination, GitOpsDataViewTable } from './DataView'; import GitOpsViewSwitcher from './GitOpsViewSwitcher'; import { APPLICATION_SET_APPLICATIONS_VIEW_SETTING_KEY, GitOpsViewType } from './GitOpsViewType'; @@ -31,6 +31,8 @@ type ApplicationSetApplicationsViewProps = { errorState?: React.ReactNode; isError?: boolean; isEmpty: boolean; + itemCount?: number; + pagination?: GitOpsDataViewPagination; }; const ApplicationSetApplicationsView: React.FC = ({ @@ -49,6 +51,8 @@ const ApplicationSetApplicationsView: React.FC { const [savedViewType, setSavedViewType, viewSettingsLoaded] = useUserSettings( APPLICATION_SET_APPLICATIONS_VIEW_SETTING_KEY, @@ -124,6 +128,8 @@ const ApplicationSetApplicationsView: React.FC { + const idRef = React.useRef(); + if (!idRef.current) { + gitOpsPaginationInstanceCounter += 1; + idRef.current = `gitops-pagination-${gitOpsPaginationInstanceCounter}`; + } + return idRef.current; +}; + type BodyStateKey = 'empty' | 'error'; export type GitOpsDataViewBodyStates = Partial>; @@ -46,6 +62,28 @@ export type GitOpsDataViewTableProps = { * the appropriate state based on isEmpty and isError. */ activeState?: DataViewState | null; + /** + * Total number of filtered items. Required when pagination is enabled so the + * pager can show "1-50 of N" against the full result set, not the current page. + */ + itemCount?: number; + /** + * Optional PF pagination state. When omitted, the table renders every row. + */ + pagination?: GitOpsDataViewPagination; +}; + +export type GitOpsDataViewPagination = { + page: number; + perPage: number; + onSetPage: ( + event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, + newPage: number, + ) => void; + onPerPageSelect: ( + event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, + newPerPage: number, + ) => void; }; const mergeBodyStates = ( @@ -73,7 +111,10 @@ export const GitOpsDataViewTable: React.FC = ({ errorState, bodyStates, activeState, + itemCount, + pagination, }) => { + const paginationWidgetIdBase = useGitOpsPaginationWidgetIdBase(); const resolvedBodyStates = React.useMemo( () => mergeBodyStates(bodyStates, { @@ -99,13 +140,69 @@ export const GitOpsDataViewTable: React.FC = ({ return null; }, [activeState, isEmpty, isError, isLoading]); + const paginationItemCount = itemCount ?? 0; + const showPagination = !!pagination && paginationItemCount > 0 && !isError && !isLoading; + return ( + {showPagination && pagination && ( + + } + /> + )} + {showPagination && pagination && ( + + } + /> + )} ); }; +const GitOpsPagination: React.FC<{ + itemCount: number; + pagination: GitOpsDataViewPagination; + variant: PaginationVariant; + widgetId: string; +}> = ({ itemCount, pagination, variant, widgetId }) => { + const { t } = useGitOpsTranslation(); + + return ( + + ); +}; + export interface GitOpsDataViewSortConfig { key: string; } @@ -169,4 +266,59 @@ export const useGitOpsDataViewSort = ( }; }; +/** + * Client-side pagination for GitOps DataView tables. Matches Console: 10/20/50/100, + * default 50, page and perPage stored in the URL. Resets to page 1 when resetKey changes + * (filters, search, namespace) and clamps when the result set shrinks. + */ +export const useGitOpsDataViewPagination = ({ + itemCount, + resetKey, +}: { + itemCount: number; + resetKey?: string; +}): GitOpsDataViewPagination => { + const [searchParams, setSearchParams] = useSearchParams(); + + const setMergedSearchParams = React.useCallback( + (params: URLSearchParams) => { + setSearchParams((prev) => { + const next = new URLSearchParams(prev); + params.forEach((value, key) => { + next.set(key, value); + }); + return next; + }); + }, + [setSearchParams], + ); + + const pagination = useDataViewPagination({ + perPage: GITOPS_DEFAULT_PER_PAGE, + searchParams, + setSearchParams: setMergedSearchParams, + }); + const { page, perPage, onSetPage } = pagination; + const previousResetKey = React.useRef(resetKey); + + React.useEffect(() => { + if (resetKey === undefined || previousResetKey.current === resetKey) { + return; + } + previousResetKey.current = resetKey; + if (page > 1) { + onSetPage(undefined, 1); + } + }, [onSetPage, page, resetKey]); + + React.useEffect(() => { + const maxPage = Math.max(1, Math.ceil(itemCount / perPage) || 1); + if (page > maxPage) { + onSetPage(undefined, maxPage); + } + }, [itemCount, onSetPage, page, perPage]); + + return pagination; +}; + type GitOpsSetSearchParams = ReturnType[1]; diff --git a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts new file mode 100644 index 000000000..544af60eb --- /dev/null +++ b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts @@ -0,0 +1,44 @@ +import { getGitOpsPaginationResetKey, paginateItems } from './gitOpsDataViewPagination'; + +describe('paginateItems', () => { + const items = ['a', 'b', 'c', 'd', 'e']; + + it('returns the first page', () => { + expect(paginateItems(items, 1, 2)).toEqual(['a', 'b']); + }); + + it('returns a middle page', () => { + expect(paginateItems(items, 2, 2)).toEqual(['c', 'd']); + }); + + it('returns a partial last page', () => { + expect(paginateItems(items, 3, 2)).toEqual(['e']); + }); + + it('treats missing items as an empty list', () => { + expect(paginateItems(undefined, 1, 50)).toEqual([]); + }); +}); + +describe('getGitOpsPaginationResetKey', () => { + it('ignores pagination and sort URL params', () => { + const params = new URLSearchParams( + 'page=3&perPage=20&sortBy=name&direction=asc&q=guestbook&rowFilter-app-sync=Synced', + ); + + expect(getGitOpsPaginationResetKey('argocd', params)).toBe( + 'argocd|q=guestbook&rowFilter-app-sync=Synced', + ); + }); + + it('changes when namespace or filters change', () => { + const params = new URLSearchParams('q=guestbook'); + + expect(getGitOpsPaginationResetKey('argocd', params)).not.toBe( + getGitOpsPaginationResetKey('openshift-gitops', params), + ); + expect(getGitOpsPaginationResetKey('argocd', params)).not.toBe( + getGitOpsPaginationResetKey('argocd', new URLSearchParams('q=other')), + ); + }); +}); diff --git a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.ts b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.ts new file mode 100644 index 000000000..7a6577dfe --- /dev/null +++ b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.ts @@ -0,0 +1,30 @@ +export const GITOPS_DEFAULT_PER_PAGE = 50; + +export const GITOPS_PER_PAGE_OPTIONS = [ + { title: '10', value: 10 }, + { title: '20', value: 20 }, + { title: '50', value: 50 }, + { title: '100', value: 100 }, +]; + +const PAGINATION_RESET_IGNORE_PARAMS = new Set(['page', 'perPage', 'sortBy', 'direction']); + +export const paginateItems = (items: T[] | undefined, page: number, perPage: number): T[] => { + const list = items ?? []; + const safePage = Math.max(page, 1); + const safePerPage = Math.max(perPage, 1); + const start = (safePage - 1) * safePerPage; + return list.slice(start, start + safePerPage); +}; + +export const getGitOpsPaginationResetKey = ( + namespace: string | null | undefined, + searchParams: URLSearchParams, +): string => { + const filtered = [...searchParams.entries()] + .filter(([key]) => !PAGINATION_RESET_IGNORE_PARAMS.has(key)) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, value]) => `${key}=${value}`) + .join('&'); + return `${namespace ?? ''}|${filtered}`; +}; diff --git a/src/gitops/components/shared/DataView/index.ts b/src/gitops/components/shared/DataView/index.ts index bb7c776b2..083b0da1b 100644 --- a/src/gitops/components/shared/DataView/index.ts +++ b/src/gitops/components/shared/DataView/index.ts @@ -1,8 +1,16 @@ +export { + getGitOpsPaginationResetKey, + GITOPS_DEFAULT_PER_PAGE, + GITOPS_PER_PAGE_OPTIONS, + paginateItems, +} from './gitOpsDataViewPagination'; export { type GitOpsDataViewBodyStates, + type GitOpsDataViewPagination, type GitOpsDataViewSortConfig, type GitOpsDataViewTableProps, type UseGitOpsDataViewSortResult, GitOpsDataViewTable, + useGitOpsDataViewPagination, useGitOpsDataViewSort, } from './GitOpsDataViewTable'; From ea46bc3cf7b105f1017faac69d9444729be424ad Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 19 Aug 2026 11:59:38 -0400 Subject: [PATCH 5/8] add pagination to other list pages && tests Signed-off-by: Atif Ali --- .../imageupdater/ImageUpdaterList.tsx | 30 +++- src/gitops/components/project/ProjectList.tsx | 30 +++- src/gitops/components/rollout/RolloutList.tsx | 46 ++++-- .../components/shared/ApplicationList.tsx | 140 ++++++---------- .../components/shared/ApplicationSetList.tsx | 43 +++-- .../shared/DataView/GitOpsDataViewTable.tsx | 42 ++++- .../DataView/gitOpsDataViewPagination.test.ts | 42 +++++ .../components/shared/DataView/index.ts | 1 + .../shared/applicationListFilters.test.ts | 155 ++++++++++++++++++ .../shared/applicationListFilters.ts | 89 ++++++++++ .../shared/listPageTextFilters.test.ts | 127 ++++++++++++++ .../components/shared/listPageTextFilters.ts | 99 +++++++++++ 12 files changed, 716 insertions(+), 128 deletions(-) create mode 100644 src/gitops/components/shared/applicationListFilters.test.ts create mode 100644 src/gitops/components/shared/applicationListFilters.ts create mode 100644 src/gitops/components/shared/listPageTextFilters.test.ts create mode 100644 src/gitops/components/shared/listPageTextFilters.ts diff --git a/src/gitops/components/imageupdater/ImageUpdaterList.tsx b/src/gitops/components/imageupdater/ImageUpdaterList.tsx index 9a183b0d2..e5163cb91 100644 --- a/src/gitops/components/imageupdater/ImageUpdaterList.tsx +++ b/src/gitops/components/imageupdater/ImageUpdaterList.tsx @@ -33,7 +33,12 @@ import { ShowOperandsInAllNamespacesRadioGroup, useShowOperandsInAllNamespaces, } from '../shared/AllNamespaces'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; +import { filterByConsoleNameAndLabels, parseLabelFilterParam } from '../shared/listPageTextFilters'; import { useImageUpdaterActionsProvider } from './hooks/useImageUpdaterActionsProvider'; @@ -80,6 +85,8 @@ const ImageUpdaterList: React.FC = ({ // Get search query from URL parameters const searchQuery = searchParams.get('q') || ''; + const nameQuery = searchParams.get('name') || ''; + const labelsParam = searchParams.get('labels') || ''; const { t } = useTranslation('plugin__gitops-plugin'); @@ -91,11 +98,17 @@ const ImageUpdaterList: React.FC = ({ const filters = getFilters(t); const [data, filteredData, onFilterChange] = useListPageFilter(sortedItems, filters); + const filteredByNameAndLabels = React.useMemo( + () => + filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + [filteredData, nameQuery, labelsParam], + ); + const filteredBySearch = React.useMemo(() => { - if (!searchQuery) return filteredData; + if (!searchQuery) return filteredByNameAndLabels; const lowerQuery = searchQuery.toLowerCase(); - return filteredData.filter((item) => { + return filteredByNameAndLabels.filter((item) => { const name = item.metadata?.name || ''; const labels = item.metadata?.labels || {}; return ( @@ -109,9 +122,14 @@ const ImageUpdaterList: React.FC = ({ }) ); }); - }, [filteredData, searchQuery]); + }, [filteredByNameAndLabels, searchQuery]); - const rows = useImageUpdaterRowsDV(filteredBySearch as ImageUpdaterKind[], effectiveNamespace); + const { pagination, pagedItems, itemCount } = useGitOpsListPagePagination({ + items: filteredBySearch as ImageUpdaterKind[], + namespace: effectiveNamespace, + searchParams, + }); + const rows = useImageUpdaterRowsDV(pagedItems, effectiveNamespace); const hasItems = React.useMemo(() => { return sortedItems.length > 0; @@ -209,6 +227,8 @@ const ImageUpdaterList: React.FC = ({ emptyState={empty} isError={!!loadError} errorState={error || undefined} + itemCount={itemCount} + pagination={pagination} />
    diff --git a/src/gitops/components/project/ProjectList.tsx b/src/gitops/components/project/ProjectList.tsx index 3eddd7d6f..7ed88ded0 100644 --- a/src/gitops/components/project/ProjectList.tsx +++ b/src/gitops/components/project/ProjectList.tsx @@ -31,7 +31,12 @@ import { ShowOperandsInAllNamespacesRadioGroup, useShowOperandsInAllNamespaces, } from '../shared/AllNamespaces'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; +import { filterByConsoleNameAndLabels, parseLabelFilterParam } from '../shared/listPageTextFilters'; import { MetadataLabels } from '../shared/MetadataLabels/MetadataLabels'; import { useProjectActionsProvider } from './hooks/useProjectActionsProvider'; @@ -96,6 +101,8 @@ const ProjectList: React.FC = ({ // Get search query from URL parameters const searchQuery = searchParams.get('q') || ''; + const nameQuery = searchParams.get('name') || ''; + const labelsParam = searchParams.get('labels') || ''; const { t } = useTranslation('plugin__gitops-plugin'); @@ -107,11 +114,17 @@ const ProjectList: React.FC = ({ const filters = getFilters(t, applications, appsLoaded); const [data, filteredData, onFilterChange] = useListPageFilter(sortedProjects, filters); + const filteredByNameAndLabels = React.useMemo( + () => + filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + [filteredData, nameQuery, labelsParam], + ); + // Filter by search query if present (after other filters) const filteredBySearch = React.useMemo(() => { - if (!searchQuery) return filteredData; + if (!searchQuery) return filteredByNameAndLabels; - return filteredData.filter((project) => { + return filteredByNameAndLabels.filter((project) => { const name = project.metadata?.name || ''; const description = project.spec?.description || ''; const labels = project.metadata?.labels || {}; @@ -131,9 +144,14 @@ const ProjectList: React.FC = ({ }) ); }); - }, [filteredData, searchQuery]); + }, [filteredByNameAndLabels, searchQuery]); - const rows = useProjectsRowsDV(filteredBySearch, namespace, applications, appsLoaded); + const { pagination, pagedItems, itemCount } = useGitOpsListPagePagination({ + items: filteredBySearch, + namespace, + searchParams, + }); + const rows = useProjectsRowsDV(pagedItems, namespace, applications, appsLoaded); const showNamespaceColumn = !namespace || namespace === ''; // Check if there are projects initially (before search) @@ -240,6 +258,8 @@ const ProjectList: React.FC = ({ emptyState={empty} isError={!!loadError} errorState={error || undefined} + itemCount={itemCount} + pagination={pagination} />
    diff --git a/src/gitops/components/rollout/RolloutList.tsx b/src/gitops/components/rollout/RolloutList.tsx index e4375bdc0..25a22cee5 100644 --- a/src/gitops/components/rollout/RolloutList.tsx +++ b/src/gitops/components/rollout/RolloutList.tsx @@ -30,7 +30,16 @@ import { ShowOperandsInAllNamespacesRadioGroup, useShowOperandsInAllNamespaces, } from '../shared/AllNamespaces'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; +import { + filterByConsoleNameAndLabels, + filterResourcesByLabelQuery, + parseLabelFilterParam, +} from '../shared/listPageTextFilters'; import { MetadataLabels } from '../shared/MetadataLabels/MetadataLabels'; import { useRolloutActionsProvider } from './hooks/useRolloutActionsProvider'; @@ -106,6 +115,8 @@ const RolloutList: React.FC = ({ // Get search query from URL parameters const searchQuery = searchParams.get('q') || ''; + const nameQuery = searchParams.get('name') || ''; + const labelsParam = searchParams.get('labels') || ''; const { t } = useGitOpsTranslation(); @@ -117,22 +128,23 @@ const RolloutList: React.FC = ({ const filters = getFilters(t); const [data, filteredData, onFilterChange] = useListPageFilter(sortedRollouts, filters); - // TODO: use alternate filter since it is deprecated. See DataTableView potentially - // Filter by search query if present (after other filters) - const filteredBySearch = React.useMemo(() => { - if (!searchQuery) return filteredData; + const filteredByNameAndLabels = React.useMemo( + () => + filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + [filteredData, nameQuery, labelsParam], + ); - return filteredData.filter((app) => { - const labels = app.metadata?.labels || {}; - // Check if any label matches the search query - return Object.entries(labels).some(([key, value]) => { - const labelSelector = `${key}=${value}`; - return labelSelector.includes(searchQuery) || key.includes(searchQuery); - }); - }); - }, [filteredData, searchQuery]); + const filteredBySearch = React.useMemo( + () => filterResourcesByLabelQuery(filteredByNameAndLabels, searchQuery), + [filteredByNameAndLabels, searchQuery], + ); - const rows = useRolloutsRowsDV(filteredBySearch, namespace, t); + const { pagination, pagedItems, itemCount } = useGitOpsListPagePagination({ + items: filteredBySearch, + namespace, + searchParams, + }); + const rows = useRolloutsRowsDV(pagedItems, namespace, t); const empty = ( @@ -204,7 +216,7 @@ const RolloutList: React.FC = ({ onFilterChange={onFilterChange} /> - {rows.length > 0 && !loadError && ( + {filteredBySearch.length > 0 && !loadError && ( {topologyLink(topologyUrl, t)} @@ -218,6 +230,8 @@ const RolloutList: React.FC = ({ emptyState={empty} isError={!!loadError} errorState={error || undefined} + itemCount={itemCount} + pagination={pagination} /> diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index 3430d815d..0fcd35dc2 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -11,7 +11,6 @@ import { ListPageFilter, ListPageHeader, ResourceLink, - RowFilter, useK8sWatchResource, useListPageFilter, } from '@openshift-console/dynamic-plugin-sdk'; @@ -42,14 +41,24 @@ import { ShowOperandsInAllNamespacesRadioGroup, useShowOperandsInAllNamespaces, } from './AllNamespaces'; +import { + APPLICATION_HEALTH_FILTER_PARAM, + APPLICATION_SYNC_FILTER_PARAM, + filterApplicationsByStatus, + getApplicationRowFilters, + parseRowFilterParam, +} from './applicationListFilters'; import ApplicationSetApplicationsView from './ApplicationSetApplicationsView'; import { - getGitOpsPaginationResetKey, GitOpsDataViewTable, - paginateItems, - useGitOpsDataViewPagination, useGitOpsDataViewSort, + useGitOpsListPagePagination, } from './DataView'; +import { + filterByConsoleNameAndLabels, + filterResourcesByLabelQuery, + parseLabelFilterParam, +} from './listPageTextFilters'; interface ApplicationProps { namespace: string; @@ -136,39 +145,49 @@ const ApplicationList: React.FC = ({ [sortedApplications, project, appset], ); - // TODO: use alternate filter since it is deprecated. See DataTableView potentially - // PatternFly filters work on owned apps only (the dataset that will be displayed) - const filters = getFilters(t); - // const filters = React.useMemo(() => getFilters(t), [t]); + // Console ListPageFilter is deprecated and its selected row-filter state can + // drift from the URL chips. Apply health/sync from the URL so the table and + // pager match what the user selected. + const filters = React.useMemo(() => getApplicationRowFilters(t), [t]); const [data, filteredData, onFilterChange] = useListPageFilter(ownedApps, filters); + const healthFilterParam = searchParams.get(APPLICATION_HEALTH_FILTER_PARAM); + const syncFilterParam = searchParams.get(APPLICATION_SYNC_FILTER_PARAM); + const nameQuery = searchParams.get('name') || ''; + const labelsParam = searchParams.get('labels') || ''; + const filteredByStatus = React.useMemo( + () => + filterApplicationsByStatus( + filteredData as ApplicationKind[], + parseRowFilterParam(healthFilterParam), + parseRowFilterParam(syncFilterParam), + ), + [filteredData, healthFilterParam, syncFilterParam], + ); - // Filter by search query if present (after other filters) - const filteredBySearch = React.useMemo(() => { - if (!searchQuery) return filteredData; - - return filteredData.filter((app) => { - const labels = app.metadata?.labels || {}; - // Check if any label matches the search query - return Object.entries(labels).some(([key, value]) => { - const labelSelector = `${key}=${value}`; - return labelSelector.includes(searchQuery) || key.includes(searchQuery); - }); - }); - }, [filteredData, searchQuery]); + const filteredByNameAndLabels = React.useMemo( + () => + filterByConsoleNameAndLabels( + filteredByStatus, + nameQuery, + parseLabelFilterParam(labelsParam), + ), + [filteredByStatus, nameQuery, labelsParam], + ); - const searchParamsKey = searchParams.toString(); - const paginationResetKey = React.useMemo( - () => getGitOpsPaginationResetKey(namespace, new URLSearchParams(searchParamsKey)), - [namespace, searchParamsKey], + const filteredBySearch = React.useMemo( + () => filterResourcesByLabelQuery(filteredByNameAndLabels, searchQuery), + [filteredByNameAndLabels, searchQuery], ); - const pagination = useGitOpsDataViewPagination({ - itemCount: filteredBySearch.length, - resetKey: paginationResetKey, + + const { + pagination, + pagedItems: pagedApplications, + itemCount, + } = useGitOpsListPagePagination({ + items: filteredBySearch, + namespace, + searchParams, }); - const pagedApplications = React.useMemo( - () => paginateItems(filteredBySearch, pagination.page, pagination.perPage), - [filteredBySearch, pagination.page, pagination.perPage], - ); const rows = useApplicationRowsDV(pagedApplications, namespace); // Check if there are applications owned by this ApplicationSet initially (before filters/search) @@ -289,7 +308,7 @@ const ApplicationList: React.FC = ({ emptyState={empty} errorState={error || undefined} isError={!!loadError} - itemCount={filteredBySearch.length} + itemCount={itemCount} pagination={pagination} /> )} @@ -301,7 +320,7 @@ const ApplicationList: React.FC = ({ emptyState={empty} errorState={error || undefined} isError={!!loadError} - itemCount={filteredBySearch.length} + itemCount={itemCount} pagination={pagination} /> )} @@ -546,57 +565,4 @@ const useColumnsDV = ( return columns; }; -const FilterUnknownStatus: string = 'Sync.' + SyncStatus.UNKNOWN; - -const getFilters = (t: (key: string) => string): RowFilter[] => [ - { - filterGroupName: t('Sync Status'), - type: 'app-sync', - reducer: (application) => - application.status?.sync?.status == SyncStatus.UNKNOWN || - application.status?.sync?.status == undefined - ? FilterUnknownStatus - : application.status?.sync?.status, - filter: (input, application) => { - if (input.selected?.length && application?.status?.sync?.status) { - return ( - input.selected.includes(application.status?.sync?.status) || - (input.selected.includes(FilterUnknownStatus) && - application.status?.sync?.status == SyncStatus.UNKNOWN) - ); - } else if (application.status?.sync?.status == undefined) { - return true; - } else if (!application?.status?.sync?.status) { - return false; - } - return true; - }, - items: [ - { id: SyncStatus.SYNCED, title: SyncStatus.SYNCED }, - { id: SyncStatus.OUT_OF_SYNC, title: SyncStatus.OUT_OF_SYNC }, - { id: FilterUnknownStatus, title: SyncStatus.UNKNOWN }, - ], - }, - { - filterGroupName: t('Health Status'), - type: 'app-health', - reducer: (application) => application.status?.health?.status, - filter: (input, application) => { - if (input.selected?.length && application?.status?.health?.status) { - return input.selected.includes(application.status?.health?.status); - } else { - return true; - } - }, - items: [ - { id: HealthStatus.UNKNOWN, title: HealthStatus.UNKNOWN }, - { id: HealthStatus.PROGRESSING, title: HealthStatus.PROGRESSING }, - { id: HealthStatus.SUSPENDED, title: HealthStatus.SUSPENDED }, - { id: HealthStatus.HEALTHY, title: HealthStatus.HEALTHY }, - { id: HealthStatus.DEGRADED, title: HealthStatus.DEGRADED }, - { id: HealthStatus.MISSING, title: HealthStatus.MISSING }, - ], - }, -]; - export default ApplicationList; diff --git a/src/gitops/components/shared/ApplicationSetList.tsx b/src/gitops/components/shared/ApplicationSetList.tsx index ae4cc9341..2c9846c67 100644 --- a/src/gitops/components/shared/ApplicationSetList.tsx +++ b/src/gitops/components/shared/ApplicationSetList.tsx @@ -37,7 +37,16 @@ import { ShowOperandsInAllNamespacesRadioGroup, useShowOperandsInAllNamespaces, } from './AllNamespaces'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from './DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from './DataView'; +import { + filterByConsoleNameAndLabels, + filterResourcesByLabelQuery, + parseLabelFilterParam, +} from './listPageTextFilters'; const formatCreationTimestamp = (timestamp: string): string => { if (!timestamp) return '-'; @@ -158,6 +167,8 @@ const ApplicationSetList: React.FC = ({ // Get search query from URL parameters const searchQuery = searchParams.get('q') || ''; + const nameQuery = searchParams.get('name') || ''; + const labelsParam = searchParams.get('labels') || ''; const columnsDV = useColumnsDV(namespace, getSortParams); const sortedApplicationSets = React.useMemo(() => { @@ -173,21 +184,23 @@ const ApplicationSetList: React.FC = ({ const filters = getFilters(t); const [data, filteredData, onFilterChange] = useListPageFilter(sortedApplicationSets, filters); - // Filter by search query if present (after other filters) - const filteredBySearch = React.useMemo(() => { - if (!searchQuery) return filteredData; + const filteredByNameAndLabels = React.useMemo( + () => + filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + [filteredData, nameQuery, labelsParam], + ); - return filteredData.filter((appSet) => { - const labels = appSet.metadata?.labels || {}; - // Check if any label matches the search query - return Object.entries(labels).some(([key, value]) => { - const labelSelector = `${key}=${value}`; - return labelSelector.includes(searchQuery) || key.includes(searchQuery); - }); - }); - }, [filteredData, searchQuery]); + const filteredBySearch = React.useMemo( + () => filterResourcesByLabelQuery(filteredByNameAndLabels, searchQuery), + [filteredByNameAndLabels, searchQuery], + ); - const rows = useApplicationSetRowsDV(filteredBySearch, namespace, applications, appsLoaded); + const { pagination, pagedItems, itemCount } = useGitOpsListPagePagination({ + items: filteredBySearch, + namespace, + searchParams, + }); + const rows = useApplicationSetRowsDV(pagedItems, namespace, applications, appsLoaded); // Check if there are ApplicationSets initially (before search) const hasApplicationSets = React.useMemo(() => { @@ -292,6 +305,8 @@ const ApplicationSetList: React.FC = ({ isLoading={!loaded} isError={!!loadError} errorState={error} + itemCount={itemCount} + pagination={pagination} activeState={ // eslint-disable-next-line no-nested-ternary !loaded ? DataViewState.loading : isEmptyState ? DataViewState.empty : undefined diff --git a/src/gitops/components/shared/DataView/GitOpsDataViewTable.tsx b/src/gitops/components/shared/DataView/GitOpsDataViewTable.tsx index 139cbfde8..1d8ea6169 100644 --- a/src/gitops/components/shared/DataView/GitOpsDataViewTable.tsx +++ b/src/gitops/components/shared/DataView/GitOpsDataViewTable.tsx @@ -12,7 +12,12 @@ import DataViewToolbar from '@patternfly/react-data-view/dist/esm/DataViewToolba import { useDataViewPagination, useDataViewSort } from '@patternfly/react-data-view/dist/esm/Hooks'; import { ThProps } from '@patternfly/react-table'; -import { GITOPS_DEFAULT_PER_PAGE, GITOPS_PER_PAGE_OPTIONS } from './gitOpsDataViewPagination'; +import { + getGitOpsPaginationResetKey, + GITOPS_DEFAULT_PER_PAGE, + GITOPS_PER_PAGE_OPTIONS, + paginateItems, +} from './gitOpsDataViewPagination'; let gitOpsPaginationInstanceCounter = 0; @@ -321,4 +326,39 @@ export const useGitOpsDataViewPagination = ({ return pagination; }; +/** + * Wires URL pagination for a filtered GitOps list: reset on filter/search/namespace + * changes, then return the current page of items for the table. + */ +export const useGitOpsListPagePagination = ({ + items, + namespace, + searchParams, +}: { + items: T[] | undefined; + namespace?: string | null; + searchParams: URLSearchParams; +}): { + pagination: GitOpsDataViewPagination; + pagedItems: T[]; + itemCount: number; +} => { + const searchParamsKey = searchParams.toString(); + const paginationResetKey = React.useMemo( + () => getGitOpsPaginationResetKey(namespace, new URLSearchParams(searchParamsKey)), + [namespace, searchParamsKey], + ); + const itemCount = items?.length ?? 0; + const pagination = useGitOpsDataViewPagination({ + itemCount, + resetKey: paginationResetKey, + }); + const pagedItems = React.useMemo( + () => paginateItems(items, pagination.page, pagination.perPage), + [items, pagination.page, pagination.perPage], + ); + + return { pagination, pagedItems, itemCount }; +}; + type GitOpsSetSearchParams = ReturnType[1]; diff --git a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts index 544af60eb..5df364c09 100644 --- a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts +++ b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts @@ -18,6 +18,18 @@ describe('paginateItems', () => { it('treats missing items as an empty list', () => { expect(paginateItems(undefined, 1, 50)).toEqual([]); }); + + it('shows page 1 when the requested page is 0', () => { + expect(paginateItems(items, 0, 2)).toEqual(['a', 'b']); + }); + + it('shows at least one item when items per page is 0', () => { + expect(paginateItems(items, 1, 0)).toEqual(['a']); + }); + + it('returns an empty page past the end of the list', () => { + expect(paginateItems(items, 10, 2)).toEqual([]); + }); }); describe('getGitOpsPaginationResetKey', () => { @@ -41,4 +53,34 @@ describe('getGitOpsPaginationResetKey', () => { getGitOpsPaginationResetKey('argocd', new URLSearchParams('q=other')), ); }); + + it('changes when health status chips change but not when only the page changes', () => { + const health = new URLSearchParams('page=2&rowFilter-app-health=Healthy'); + const nextPage = new URLSearchParams('page=3&rowFilter-app-health=Healthy'); + const otherHealth = new URLSearchParams('page=2&rowFilter-app-health=Degraded'); + + expect(getGitOpsPaginationResetKey('argocd', health)).toBe( + getGitOpsPaginationResetKey('argocd', nextPage), + ); + expect(getGitOpsPaginationResetKey('argocd', health)).not.toBe( + getGitOpsPaginationResetKey('argocd', otherHealth), + ); + }); + + it('changes when name or label chips change but not when only the page changes', () => { + const named = new URLSearchParams('page=2&name=appsss'); + const nextPage = new URLSearchParams('page=3&name=appsss'); + const otherName = new URLSearchParams('page=2&name=guestbook'); + const labeled = new URLSearchParams('page=2&labels=app=guestbook'); + + expect(getGitOpsPaginationResetKey('argocd', named)).toBe( + getGitOpsPaginationResetKey('argocd', nextPage), + ); + expect(getGitOpsPaginationResetKey('argocd', named)).not.toBe( + getGitOpsPaginationResetKey('argocd', otherName), + ); + expect(getGitOpsPaginationResetKey('argocd', named)).not.toBe( + getGitOpsPaginationResetKey('argocd', labeled), + ); + }); }); diff --git a/src/gitops/components/shared/DataView/index.ts b/src/gitops/components/shared/DataView/index.ts index 083b0da1b..e973ddd7e 100644 --- a/src/gitops/components/shared/DataView/index.ts +++ b/src/gitops/components/shared/DataView/index.ts @@ -13,4 +13,5 @@ export { GitOpsDataViewTable, useGitOpsDataViewPagination, useGitOpsDataViewSort, + useGitOpsListPagePagination, } from './GitOpsDataViewTable'; diff --git a/src/gitops/components/shared/applicationListFilters.test.ts b/src/gitops/components/shared/applicationListFilters.test.ts new file mode 100644 index 000000000..ad41e217e --- /dev/null +++ b/src/gitops/components/shared/applicationListFilters.test.ts @@ -0,0 +1,155 @@ +import { HealthStatus, SyncStatus } from '../../utils/constants'; + +import { + APPLICATION_SYNC_UNKNOWN_FILTER_ID, + filterApplicationsByStatus, + getApplicationHealthStatus, + getApplicationSyncFilterId, + matchesApplicationHealthFilter, + matchesApplicationSyncFilter, + parseRowFilterParam, +} from './applicationListFilters'; +import { paginateItems } from './DataView/gitOpsDataViewPagination'; + +const app = ( + name: string, + health?: string, + sync?: string, + labels?: Record, +) => + ({ + metadata: { name, labels }, + spec: { project: 'default' }, + status: { + health: health ? { status: health } : undefined, + sync: sync ? { status: sync } : undefined, + }, + } as any); + +describe('parseRowFilterParam', () => { + it('splits Console rowFilter query values', () => { + expect(parseRowFilterParam('Healthy,Degraded')).toEqual(['Healthy', 'Degraded']); + }); + + it('returns an empty list when unset', () => { + expect(parseRowFilterParam(null)).toEqual([]); + expect(parseRowFilterParam('')).toEqual([]); + }); +}); + +describe('application health filter', () => { + it('treats missing health as Unknown', () => { + expect(getApplicationHealthStatus(app('none'))).toBe(HealthStatus.UNKNOWN); + expect(getApplicationHealthStatus(app('ok', HealthStatus.HEALTHY))).toBe(HealthStatus.HEALTHY); + }); + + it('passes all apps when nothing is selected', () => { + expect(matchesApplicationHealthFilter([], app('missing', HealthStatus.MISSING))).toBe(true); + expect(matchesApplicationHealthFilter(undefined, app('none'))).toBe(true); + }); + + it('keeps Healthy and Degraded and drops Missing', () => { + const selected = [HealthStatus.HEALTHY, HealthStatus.DEGRADED]; + expect(matchesApplicationHealthFilter(selected, app('ok', HealthStatus.HEALTHY))).toBe(true); + expect(matchesApplicationHealthFilter(selected, app('bad', HealthStatus.DEGRADED))).toBe(true); + expect(matchesApplicationHealthFilter(selected, app('gone', HealthStatus.MISSING))).toBe(false); + expect( + matchesApplicationHealthFilter(selected, app('wait', HealthStatus.PROGRESSING)), + ).toBe(false); + }); + + it('does not keep apps with no health status when Healthy is selected', () => { + expect(matchesApplicationHealthFilter([HealthStatus.HEALTHY], app('none'))).toBe(false); + }); + + it('filters a list to the selected health statuses', () => { + const apps = [ + app('a', HealthStatus.HEALTHY), + app('b', HealthStatus.MISSING), + app('c', HealthStatus.PROGRESSING), + app('d', HealthStatus.HEALTHY), + ]; + expect( + filterApplicationsByStatus(apps, [HealthStatus.HEALTHY, HealthStatus.DEGRADED], []), + ).toHaveLength(2); + }); +}); + +describe('application sync filter', () => { + it('maps missing and Unknown sync to the Unknown filter id', () => { + expect(getApplicationSyncFilterId(app('none'))).toBe(APPLICATION_SYNC_UNKNOWN_FILTER_ID); + expect( + getApplicationSyncFilterId(app('unknown', HealthStatus.HEALTHY, SyncStatus.UNKNOWN)), + ).toBe(APPLICATION_SYNC_UNKNOWN_FILTER_ID); + expect(getApplicationSyncFilterId(app('ok', HealthStatus.HEALTHY, SyncStatus.SYNCED))).toBe( + SyncStatus.SYNCED, + ); + }); + + it('does not keep unknown/missing sync when Synced is selected', () => { + expect( + matchesApplicationSyncFilter([SyncStatus.SYNCED], app('none', HealthStatus.HEALTHY)), + ).toBe(false); + expect( + matchesApplicationSyncFilter( + [SyncStatus.SYNCED], + app('unknown', HealthStatus.HEALTHY, SyncStatus.UNKNOWN), + ), + ).toBe(false); + }); + + it('filters by sync independently of health', () => { + const apps = [ + app('synced', HealthStatus.HEALTHY, SyncStatus.SYNCED), + app('out', HealthStatus.HEALTHY, SyncStatus.OUT_OF_SYNC), + ]; + expect(filterApplicationsByStatus(apps, [], [SyncStatus.SYNCED])).toHaveLength(1); + expect(filterApplicationsByStatus(apps, [], [SyncStatus.SYNCED])[0].metadata.name).toBe( + 'synced', + ); + }); +}); + +describe('application list sort, filter, and pagination', () => { + const apps = [ + app('zeta', HealthStatus.HEALTHY, SyncStatus.SYNCED, { app: 'guestbook' }), + app('alpha', HealthStatus.MISSING, SyncStatus.OUT_OF_SYNC, { team: 'platform' }), + app('beta', HealthStatus.HEALTHY, SyncStatus.SYNCED, { env: 'prod' }), + app('gamma', HealthStatus.DEGRADED, SyncStatus.OUT_OF_SYNC), + app('delta', HealthStatus.HEALTHY, SyncStatus.SYNCED, { app: 'demo' }), + ]; + + const byName = (items: { metadata: { name: string } }[]) => + [...items].sort((left, right) => left.metadata.name.localeCompare(right.metadata.name)); + + it('sorts then filters by health, then paginates', () => { + const sorted = byName(apps); + expect(sorted.map((item) => item.metadata.name)).toEqual([ + 'alpha', + 'beta', + 'delta', + 'gamma', + 'zeta', + ]); + + const healthy = filterApplicationsByStatus(sorted, [HealthStatus.HEALTHY], []); + expect(healthy.map((item) => item.metadata.name)).toEqual(['beta', 'delta', 'zeta']); + + expect(paginateItems(healthy, 1, 2).map((item) => item.metadata.name)).toEqual([ + 'beta', + 'delta', + ]); + expect(paginateItems(healthy, 2, 2).map((item) => item.metadata.name)).toEqual(['zeta']); + }); + + it('applies health and sync together before paging', () => { + const healthySynced = filterApplicationsByStatus( + byName(apps), + [HealthStatus.HEALTHY], + [SyncStatus.SYNCED], + ); + expect(healthySynced.map((item) => item.metadata.name)).toEqual(['beta', 'delta', 'zeta']); + expect(paginateItems(healthySynced, 1, 2)).toHaveLength(2); + expect(paginateItems(healthySynced, 1, 2)[0].metadata.name).toBe('beta'); + }); +}); diff --git a/src/gitops/components/shared/applicationListFilters.ts b/src/gitops/components/shared/applicationListFilters.ts new file mode 100644 index 000000000..bf9ed6d0a --- /dev/null +++ b/src/gitops/components/shared/applicationListFilters.ts @@ -0,0 +1,89 @@ +import { RowFilter } from '@openshift-console/dynamic-plugin-sdk'; + +import { ApplicationKind } from '../../models/ApplicationModel'; +import { HealthStatus, SyncStatus } from '../../utils/constants'; + +export const APPLICATION_SYNC_FILTER_TYPE = 'app-sync'; +export const APPLICATION_HEALTH_FILTER_TYPE = 'app-health'; +export const APPLICATION_SYNC_FILTER_PARAM = `rowFilter-${APPLICATION_SYNC_FILTER_TYPE}`; +export const APPLICATION_HEALTH_FILTER_PARAM = `rowFilter-${APPLICATION_HEALTH_FILTER_TYPE}`; +export const APPLICATION_SYNC_UNKNOWN_FILTER_ID = `Sync.${SyncStatus.UNKNOWN}`; + +export const getApplicationHealthStatus = ( + application: Pick | undefined, +): HealthStatus => (application?.status?.health?.status as HealthStatus) || HealthStatus.UNKNOWN; + +export const getApplicationSyncFilterId = ( + application: Pick | undefined, +): string => { + const status = application?.status?.sync?.status; + if (!status || status === SyncStatus.UNKNOWN) { + return APPLICATION_SYNC_UNKNOWN_FILTER_ID; + } + return status; +}; + +export const parseRowFilterParam = (value: string | null | undefined): string[] => + (value ?? '') + .split(',') + .map((item) => item.trim()) + .filter(Boolean); + +export const matchesApplicationHealthFilter = ( + selected: string[] | undefined, + application: Pick | undefined, +): boolean => { + if (!selected?.length) { + return true; + } + return selected.includes(getApplicationHealthStatus(application)); +}; + +export const matchesApplicationSyncFilter = ( + selected: string[] | undefined, + application: Pick | undefined, +): boolean => { + if (!selected?.length) { + return true; + } + return selected.includes(getApplicationSyncFilterId(application)); +}; + +export const filterApplicationsByStatus = ( + applications: ApplicationKind[] | undefined, + healthSelected: string[], + syncSelected: string[], +): ApplicationKind[] => + (applications ?? []).filter( + (application) => + matchesApplicationHealthFilter(healthSelected, application) && + matchesApplicationSyncFilter(syncSelected, application), + ); + +export const getApplicationRowFilters = (t: (key: string) => string): RowFilter[] => [ + { + filterGroupName: t('Sync Status'), + type: APPLICATION_SYNC_FILTER_TYPE, + reducer: (application) => getApplicationSyncFilterId(application), + filter: (input, application) => matchesApplicationSyncFilter(input.selected, application), + items: [ + { id: SyncStatus.SYNCED, title: SyncStatus.SYNCED }, + { id: SyncStatus.OUT_OF_SYNC, title: SyncStatus.OUT_OF_SYNC }, + { id: APPLICATION_SYNC_UNKNOWN_FILTER_ID, title: SyncStatus.UNKNOWN }, + ], + }, + { + filterGroupName: t('Health Status'), + type: APPLICATION_HEALTH_FILTER_TYPE, + reducer: (application) => getApplicationHealthStatus(application), + filter: (input, application) => matchesApplicationHealthFilter(input.selected, application), + items: [ + { id: HealthStatus.UNKNOWN, title: HealthStatus.UNKNOWN }, + { id: HealthStatus.PROGRESSING, title: HealthStatus.PROGRESSING }, + { id: HealthStatus.SUSPENDED, title: HealthStatus.SUSPENDED }, + { id: HealthStatus.HEALTHY, title: HealthStatus.HEALTHY }, + { id: HealthStatus.DEGRADED, title: HealthStatus.DEGRADED }, + { id: HealthStatus.MISSING, title: HealthStatus.MISSING }, + ], + }, +]; diff --git a/src/gitops/components/shared/listPageTextFilters.test.ts b/src/gitops/components/shared/listPageTextFilters.test.ts new file mode 100644 index 000000000..ebb073baa --- /dev/null +++ b/src/gitops/components/shared/listPageTextFilters.test.ts @@ -0,0 +1,127 @@ +import { paginateItems } from './DataView/gitOpsDataViewPagination'; +import { + filterByConsoleNameAndLabels, + filterResourcesByLabelQuery, + fuzzySearch, + matchesConsoleLabelFilter, + matchesConsoleNameFilter, + matchesLabelSearchQuery, + parseLabelFilterParam, +} from './listPageTextFilters'; + +const resource = (name: string, labels?: Record) => ({ + metadata: { name, labels }, +}); + +describe('fuzzySearch (Console Name filter)', () => { + it('matches when query letters appear in order, including the Application screenshot case', () => { + expect(fuzzySearch('appsss', 'app-matrix-2-staging-us-east')).toBe(true); + expect(fuzzySearch('appsss', 'app-matrix-2-staging-us-west')).toBe(true); + }); + + it('matches the ApplicationSet screenshot case', () => { + expect(fuzzySearch('testss', 'test-sorting-appset')).toBe(true); + expect(fuzzySearch('testss', 'test-sorting-single-generator')).toBe(true); + }); + + it('does not match when letters are missing or out of order', () => { + expect(fuzzySearch('appsss', 'guestbook')).toBe(false); + expect(fuzzySearch('zzz', 'app-matrix-2-staging-us-east')).toBe(false); + expect(fuzzySearch('ssa', 'app')).toBe(false); + }); + + it('matches an exact or contiguous substring', () => { + expect(fuzzySearch('guestbook', 'guestbook')).toBe(true); + expect(fuzzySearch('book', 'guestbook')).toBe(true); + }); +}); + +describe('matchesConsoleNameFilter', () => { + it('keeps every resource when the name query is empty', () => { + expect(matchesConsoleNameFilter('', 'guestbook')).toBe(true); + expect(matchesConsoleNameFilter(null, 'guestbook')).toBe(true); + }); + + it('is case-insensitive', () => { + expect(matchesConsoleNameFilter('APP', 'app-matrix-2-staging-us-east')).toBe(true); + expect(matchesConsoleNameFilter('TestSS', 'test-sorting-appset')).toBe(true); + }); +}); + +describe('matchesConsoleLabelFilter', () => { + const labels = { app: 'guestbook', env: 'prod' }; + + it('keeps every resource when no label chips are selected', () => { + expect(matchesConsoleLabelFilter([], labels)).toBe(true); + expect(matchesConsoleLabelFilter(undefined, labels)).toBe(true); + }); + + it('requires every chip to match a key=value label', () => { + expect(matchesConsoleLabelFilter(['app=guestbook'], labels)).toBe(true); + expect(matchesConsoleLabelFilter(['app=guestbook', 'env=prod'], labels)).toBe(true); + expect(matchesConsoleLabelFilter(['app=guestbook', 'env=stage'], labels)).toBe(false); + expect(matchesConsoleLabelFilter(['team=platform'], labels)).toBe(false); + }); + + it('parses Console labels query values', () => { + expect(parseLabelFilterParam('app=guestbook,env=prod')).toEqual(['app=guestbook', 'env=prod']); + expect(parseLabelFilterParam(null)).toEqual([]); + }); +}); + +describe('matchesLabelSearchQuery (GitOps q param)', () => { + const labels = { app: 'guestbook', env: 'prod' }; + + it('matches label keys and key=value, and ignores resource name', () => { + expect(matchesLabelSearchQuery('', labels)).toBe(true); + expect(matchesLabelSearchQuery('guestbook', labels)).toBe(true); + expect(matchesLabelSearchQuery('app=', labels)).toBe(true); + expect(matchesLabelSearchQuery('env', labels)).toBe(true); + expect(matchesLabelSearchQuery('missing', labels)).toBe(false); + expect(matchesLabelSearchQuery('guestbook', undefined)).toBe(false); + }); +}); + +describe('name and label filters with pagination', () => { + const items = [ + resource('app-matrix-2-staging-us-east', { app: 'matrix' }), + resource('app-matrix-2-staging-us-west', { app: 'matrix' }), + resource('guestbook', { app: 'guestbook' }), + resource('test-sorting-appset'), + ]; + + it('filters by Console name then paginates the filtered set', () => { + const named = filterByConsoleNameAndLabels(items, 'appsss', []); + expect(named.map((item) => item.metadata.name)).toEqual([ + 'app-matrix-2-staging-us-east', + 'app-matrix-2-staging-us-west', + ]); + expect(paginateItems(named, 1, 1).map((item) => item.metadata.name)).toEqual([ + 'app-matrix-2-staging-us-east', + ]); + expect(paginateItems(named, 2, 1).map((item) => item.metadata.name)).toEqual([ + 'app-matrix-2-staging-us-west', + ]); + }); + + it('filters by Console labels then paginates', () => { + const labeled = filterByConsoleNameAndLabels(items, '', ['app=guestbook']); + expect(labeled.map((item) => item.metadata.name)).toEqual(['guestbook']); + expect(paginateItems(labeled, 1, 50)).toHaveLength(1); + }); + + it('applies name and labels together', () => { + const both = filterByConsoleNameAndLabels(items, 'appsss', ['app=matrix']); + expect(both.map((item) => item.metadata.name)).toEqual([ + 'app-matrix-2-staging-us-east', + 'app-matrix-2-staging-us-west', + ]); + expect(filterByConsoleNameAndLabels(items, 'appsss', ['app=guestbook'])).toEqual([]); + }); + + it('applies the q label search without matching names', () => { + const byQ = filterResourcesByLabelQuery(items, 'guestbook'); + expect(byQ.map((item) => item.metadata.name)).toEqual(['guestbook']); + expect(filterResourcesByLabelQuery(items, 'app-matrix')).toEqual([]); + }); +}); diff --git a/src/gitops/components/shared/listPageTextFilters.ts b/src/gitops/components/shared/listPageTextFilters.ts new file mode 100644 index 000000000..af1d113e7 --- /dev/null +++ b/src/gitops/components/shared/listPageTextFilters.ts @@ -0,0 +1,99 @@ +type LabeledResource = { + metadata?: { + name?: string; + labels?: Record; + }; +}; + +/** + * Console ListPageFilter Name filter uses fuzzysearch on metadata.name + * (case-insensitive). Letters of the query must appear in order, not as a + * contiguous substring. + */ +export const fuzzySearch = (needle: string, haystack: string): boolean => { + const needleLength = needle.length; + const haystackLength = haystack.length; + if (needleLength > haystackLength) { + return false; + } + if (needleLength === haystackLength) { + return needle === haystack; + } + let haystackIndex = 0; + for (let needleIndex = 0; needleIndex < needleLength; needleIndex++) { + const needleCode = needle.charCodeAt(needleIndex); + let found = false; + while (haystackIndex < haystackLength) { + if (haystack.charCodeAt(haystackIndex++) === needleCode) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; +}; + +export const matchesConsoleNameFilter = ( + query: string | null | undefined, + name: string | undefined, +): boolean => { + if (!query) { + return true; + } + return fuzzySearch(query.toLowerCase(), (name || '').toLowerCase()); +}; + +export const parseLabelFilterParam = (value: string | null | undefined): string[] => + (value ?? '') + .split(',') + .map((item) => item.trim()) + .filter(Boolean); + +export const matchesConsoleLabelFilter = ( + selected: string[] | undefined, + labels: Record | undefined, +): boolean => { + if (!selected?.length) { + return true; + } + const labelStrings = Object.entries(labels || {}).map(([key, val]) => `${key}=${val ?? ''}`); + return selected.every((chip) => labelStrings.some((label) => label.includes(chip))); +}; + +/** Extra GitOps `q` pass used by list pages: match label key or key=value. */ +export const matchesLabelSearchQuery = ( + query: string, + labels: Record | undefined, +): boolean => { + if (!query) { + return true; + } + return Object.entries(labels || {}).some(([key, value]) => { + const labelSelector = `${key}=${value}`; + return labelSelector.includes(query) || key.includes(query); + }); +}; + +export const filterByConsoleNameAndLabels = ( + items: T[] | undefined, + nameQuery: string | null | undefined, + labelChips: string[] | undefined, +): T[] => + (items ?? []).filter( + (item) => + matchesConsoleNameFilter(nameQuery, item.metadata?.name) && + matchesConsoleLabelFilter(labelChips, item.metadata?.labels), + ); + +export const filterResourcesByLabelQuery = ( + items: T[] | undefined, + query: string, +): T[] => { + if (!query) { + return items ?? []; + } + return (items ?? []).filter((item) => matchesLabelSearchQuery(query, item.metadata?.labels)); +}; From beb51bc881a38605c84b8d00141829f9c8aa601d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 19 Aug 2026 13:33:45 -0400 Subject: [PATCH 6/8] apply coderabbit review comments Signed-off-by: Atif Ali --- .../imageupdater/ImageUpdaterList.tsx | 3 +-- src/gitops/components/project/ProjectList.tsx | 3 +-- src/gitops/components/rollout/RolloutList.tsx | 3 +-- .../components/shared/ApplicationList.tsx | 17 ++++++----------- .../components/shared/ApplicationSetList.tsx | 3 +-- .../shared/applicationListFilters.test.ts | 13 ++++--------- .../shared/listPageTextFilters.test.ts | 1 + .../components/shared/listPageTextFilters.ts | 6 +++++- 8 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/gitops/components/imageupdater/ImageUpdaterList.tsx b/src/gitops/components/imageupdater/ImageUpdaterList.tsx index b11a33948..394192449 100644 --- a/src/gitops/components/imageupdater/ImageUpdaterList.tsx +++ b/src/gitops/components/imageupdater/ImageUpdaterList.tsx @@ -101,8 +101,7 @@ const ImageUpdaterList: React.FC = ({ const [data, filteredData, onFilterChange] = useListPageFilter(sortedItems, filters); const filteredByNameAndLabels = React.useMemo( - () => - filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + () => filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), [filteredData, nameQuery, labelsParam], ); diff --git a/src/gitops/components/project/ProjectList.tsx b/src/gitops/components/project/ProjectList.tsx index 3b0bd8c1d..91785110b 100644 --- a/src/gitops/components/project/ProjectList.tsx +++ b/src/gitops/components/project/ProjectList.tsx @@ -115,8 +115,7 @@ const ProjectList: React.FC = ({ const [data, filteredData, onFilterChange] = useListPageFilter(sortedProjects, filters); const filteredByNameAndLabels = React.useMemo( - () => - filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + () => filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), [filteredData, nameQuery, labelsParam], ); diff --git a/src/gitops/components/rollout/RolloutList.tsx b/src/gitops/components/rollout/RolloutList.tsx index 3bee46904..2fcf7bba6 100644 --- a/src/gitops/components/rollout/RolloutList.tsx +++ b/src/gitops/components/rollout/RolloutList.tsx @@ -129,8 +129,7 @@ const RolloutList: React.FC = ({ const [data, filteredData, onFilterChange] = useListPageFilter(sortedRollouts, filters); const filteredByNameAndLabels = React.useMemo( - () => - filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + () => filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), [filteredData, nameQuery, labelsParam], ); diff --git a/src/gitops/components/shared/ApplicationList.tsx b/src/gitops/components/shared/ApplicationList.tsx index 20a8b3ce9..9ba22a1a8 100644 --- a/src/gitops/components/shared/ApplicationList.tsx +++ b/src/gitops/components/shared/ApplicationList.tsx @@ -147,11 +147,10 @@ const ApplicationList: React.FC = ({ [sortedApplications, project, appset], ); - // Console ListPageFilter is deprecated and its selected row-filter state can - // drift from the URL chips. Apply health/sync from the URL so the table and - // pager match what the user selected. + // Apply the URL chips to the full owned list so the table and pager match + // what the user selected, even if the Console filter hook is out of date. const filters = React.useMemo(() => getApplicationRowFilters(t), [t]); - const [data, filteredData, onFilterChange] = useListPageFilter(ownedApps, filters); + const [data, , onFilterChange] = useListPageFilter(ownedApps, filters); const healthFilterParam = searchParams.get(APPLICATION_HEALTH_FILTER_PARAM); const syncFilterParam = searchParams.get(APPLICATION_SYNC_FILTER_PARAM); const nameQuery = searchParams.get('name') || ''; @@ -159,20 +158,16 @@ const ApplicationList: React.FC = ({ const filteredByStatus = React.useMemo( () => filterApplicationsByStatus( - filteredData as ApplicationKind[], + data as ApplicationKind[], parseRowFilterParam(healthFilterParam), parseRowFilterParam(syncFilterParam), ), - [filteredData, healthFilterParam, syncFilterParam], + [data, healthFilterParam, syncFilterParam], ); const filteredByNameAndLabels = React.useMemo( () => - filterByConsoleNameAndLabels( - filteredByStatus, - nameQuery, - parseLabelFilterParam(labelsParam), - ), + filterByConsoleNameAndLabels(filteredByStatus, nameQuery, parseLabelFilterParam(labelsParam)), [filteredByStatus, nameQuery, labelsParam], ); diff --git a/src/gitops/components/shared/ApplicationSetList.tsx b/src/gitops/components/shared/ApplicationSetList.tsx index edec8f761..82f2dc053 100644 --- a/src/gitops/components/shared/ApplicationSetList.tsx +++ b/src/gitops/components/shared/ApplicationSetList.tsx @@ -187,8 +187,7 @@ const ApplicationSetList: React.FC = ({ const [data, filteredData, onFilterChange] = useListPageFilter(sortedApplicationSets, filters); const filteredByNameAndLabels = React.useMemo( - () => - filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), + () => filterByConsoleNameAndLabels(filteredData, nameQuery, parseLabelFilterParam(labelsParam)), [filteredData, nameQuery, labelsParam], ); diff --git a/src/gitops/components/shared/applicationListFilters.test.ts b/src/gitops/components/shared/applicationListFilters.test.ts index ad41e217e..41284b4a4 100644 --- a/src/gitops/components/shared/applicationListFilters.test.ts +++ b/src/gitops/components/shared/applicationListFilters.test.ts @@ -11,12 +11,7 @@ import { } from './applicationListFilters'; import { paginateItems } from './DataView/gitOpsDataViewPagination'; -const app = ( - name: string, - health?: string, - sync?: string, - labels?: Record, -) => +const app = (name: string, health?: string, sync?: string, labels?: Record) => ({ metadata: { name, labels }, spec: { project: 'default' }, @@ -53,9 +48,9 @@ describe('application health filter', () => { expect(matchesApplicationHealthFilter(selected, app('ok', HealthStatus.HEALTHY))).toBe(true); expect(matchesApplicationHealthFilter(selected, app('bad', HealthStatus.DEGRADED))).toBe(true); expect(matchesApplicationHealthFilter(selected, app('gone', HealthStatus.MISSING))).toBe(false); - expect( - matchesApplicationHealthFilter(selected, app('wait', HealthStatus.PROGRESSING)), - ).toBe(false); + expect(matchesApplicationHealthFilter(selected, app('wait', HealthStatus.PROGRESSING))).toBe( + false, + ); }); it('does not keep apps with no health status when Healthy is selected', () => { diff --git a/src/gitops/components/shared/listPageTextFilters.test.ts b/src/gitops/components/shared/listPageTextFilters.test.ts index ebb073baa..2698f8107 100644 --- a/src/gitops/components/shared/listPageTextFilters.test.ts +++ b/src/gitops/components/shared/listPageTextFilters.test.ts @@ -75,6 +75,7 @@ describe('matchesLabelSearchQuery (GitOps q param)', () => { it('matches label keys and key=value, and ignores resource name', () => { expect(matchesLabelSearchQuery('', labels)).toBe(true); expect(matchesLabelSearchQuery('guestbook', labels)).toBe(true); + expect(matchesLabelSearchQuery('GUESTBOOK', labels)).toBe(true); expect(matchesLabelSearchQuery('app=', labels)).toBe(true); expect(matchesLabelSearchQuery('env', labels)).toBe(true); expect(matchesLabelSearchQuery('missing', labels)).toBe(false); diff --git a/src/gitops/components/shared/listPageTextFilters.ts b/src/gitops/components/shared/listPageTextFilters.ts index af1d113e7..50ee5760c 100644 --- a/src/gitops/components/shared/listPageTextFilters.ts +++ b/src/gitops/components/shared/listPageTextFilters.ts @@ -71,9 +71,13 @@ export const matchesLabelSearchQuery = ( if (!query) { return true; } + const normalizedQuery = query.toLowerCase(); return Object.entries(labels || {}).some(([key, value]) => { const labelSelector = `${key}=${value}`; - return labelSelector.includes(query) || key.includes(query); + return ( + labelSelector.toLowerCase().includes(normalizedQuery) || + key.toLowerCase().includes(normalizedQuery) + ); }); }; From 86a584113b65d3576b259ccc14fdc6fe3d7454c7 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Thu, 20 Aug 2026 14:21:06 -0400 Subject: [PATCH 7/8] Add pagination to the other tables under details tabs Signed-off-by: Atif Ali --- .../application/ApplicationResourcesView.tsx | 23 ++++- .../application/ApplicationSourcesTab.tsx | 19 +++- .../application/ApplicationSyncStatusTab.tsx | 23 ++++- .../application/History/History.tsx | 34 +++++-- .../ImageUpdaterRecentUpdatesTab.tsx | 25 ++++- .../components/project/ProjectRolesTab.tsx | 23 ++++- .../project/ProjectSyncWindowsTab.tsx | 23 ++++- .../rollout/components/PodList/PodList.tsx | 20 +++- .../DataView/gitOpsDataViewPagination.test.ts | 97 ++++++++++++++++++- 9 files changed, 257 insertions(+), 30 deletions(-) diff --git a/src/gitops/components/application/ApplicationResourcesView.tsx b/src/gitops/components/application/ApplicationResourcesView.tsx index 0e2ea4bb4..1299c95e6 100644 --- a/src/gitops/components/application/ApplicationResourcesView.tsx +++ b/src/gitops/components/application/ApplicationResourcesView.tsx @@ -25,7 +25,11 @@ import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/Dat import { CubesIcon } from '@patternfly/react-icons'; import { Tbody, Td, Tr } from '@patternfly/react-table'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; import ResourceActionsCell from '../shared/ResourceActionsCell/ResourceActionsCell'; import { ApplicationGraphView } from './graph/ApplicationGraphView'; @@ -57,7 +61,8 @@ const ApplicationResourcesView: React.FC = ({ [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useResourceColumnsDV(getSortParams); const sortedResources = React.useMemo( () => sortData(resources, sortBy, direction), @@ -79,8 +84,18 @@ const ApplicationResourcesView: React.FC = ({ resourceFilters, ); + const { + pagination, + pagedItems: pagedResources, + itemCount, + } = useGitOpsListPagePagination({ + items: filteredResources, + namespace: application?.metadata?.namespace, + searchParams, + }); + const isEmptyResources = filteredResources.length === 0; - const rows = useResourceRowsDV(filteredResources, application, argoBaseURL); + const rows = useResourceRowsDV(pagedResources, application, argoBaseURL); const isListView = viewType === ApplicationResourcesViewType.list; const empty = ( @@ -141,6 +156,8 @@ const ApplicationResourcesView: React.FC = ({ emptyState={empty} isEmpty={isEmptyResources} activeState={isEmptyResources ? DataViewState.empty : null} + itemCount={itemCount} + pagination={pagination} /> ) : (
    diff --git a/src/gitops/components/application/ApplicationSourcesTab.tsx b/src/gitops/components/application/ApplicationSourcesTab.tsx index 0be06e65d..87d80eb74 100644 --- a/src/gitops/components/application/ApplicationSourcesTab.tsx +++ b/src/gitops/components/application/ApplicationSourcesTab.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { RouteComponentProps } from 'react-router'; +import { useSearchParams } from 'react-router-dom-v5-compat'; import { useArgoServer } from '@gitops/hooks/useArgoServer'; import { ApplicationKind, ApplicationSource } from '@gitops/models/ApplicationModel'; @@ -23,7 +24,7 @@ import { CubesIcon, GithubIcon } from '@patternfly/react-icons'; import { Tbody, Td, Tr } from '@patternfly/react-table'; import ArgoCDLink from '../shared/ArgoCDLink/ArgoCDLink'; -import { GitOpsDataViewTable } from '../shared/DataView'; +import { GitOpsDataViewTable, useGitOpsListPagePagination } from '../shared/DataView'; type ApplicationDetailsTabProps = RouteComponentProps<{ ns: string; @@ -181,7 +182,17 @@ export const useRowsDV = (sources: ApplicationSource[]): DataViewTr[] => { export const SourceList: React.FC = ({ sources, obj, argoServer }) => { const columns = useColumnsDV(); - const rows = useRowsDV(sources); + const [searchParams] = useSearchParams(); + const { + pagination, + pagedItems: pagedSources, + itemCount, + } = useGitOpsListPagePagination({ + items: sources, + namespace: obj?.metadata?.namespace, + searchParams, + }); + const rows = useRowsDV(pagedSources); const argoUrl = getApplicationArgoUrl(argoServer, obj); const empty = ( @@ -215,7 +226,9 @@ export const SourceList: React.FC = ({ sources, obj, argoServer rows={rows} columns={columns} emptyState={empty} - isEmpty={rows.length === 0} + isEmpty={sources.length === 0} + itemCount={itemCount} + pagination={pagination} /> ); diff --git a/src/gitops/components/application/ApplicationSyncStatusTab.tsx b/src/gitops/components/application/ApplicationSyncStatusTab.tsx index c4052acc1..af050cdc5 100644 --- a/src/gitops/components/application/ApplicationSyncStatusTab.tsx +++ b/src/gitops/components/application/ApplicationSyncStatusTab.tsx @@ -34,7 +34,11 @@ import { CubesIcon } from '@patternfly/react-icons'; import { Tbody, Td, ThProps, Tr } from '@patternfly/react-table'; import { DetailsDescriptionGroup } from '../shared/BaseDetailsSummary/BaseDetailsSummary'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; import ResourceActionsCell from '../shared/ResourceActionsCell/ResourceActionsCell'; import { ConditionsPopover } from './Conditions/ConditionsPopover'; @@ -62,13 +66,24 @@ const ApplicationSyncStatusTab: React.FC = ({ obj [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useResourceColumnsDV(getSortParams); const sortedResources = React.useMemo(() => { return sortData(resources, sortBy, direction); }, [resources, sortBy, direction]); - const rows = useResourceRowsDV(sortedResources, obj, argoUrl); + const { + pagination, + pagedItems: pagedResources, + itemCount, + } = useGitOpsListPagePagination({ + items: sortedResources, + namespace: obj?.metadata?.namespace, + searchParams, + }); + + const rows = useResourceRowsDV(pagedResources, obj, argoUrl); const empty = ( @@ -247,6 +262,8 @@ const ApplicationSyncStatusTab: React.FC = ({ obj emptyState={empty} isEmpty={sortedResources.length === 0} activeState={resources.length === 0 ? DataViewState.empty : null} + itemCount={itemCount} + pagination={pagination} />
    diff --git a/src/gitops/components/application/History/History.tsx b/src/gitops/components/application/History/History.tsx index bb7619043..410c6f77f 100644 --- a/src/gitops/components/application/History/History.tsx +++ b/src/gitops/components/application/History/History.tsx @@ -14,7 +14,11 @@ import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/Dat import { CubesIcon } from '@patternfly/react-icons'; import { Tbody, Td, ThProps, Tr } from '@patternfly/react-table'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../../shared/DataView'; import './History.scss'; @@ -30,14 +34,26 @@ const HistoryList: React.FC = ({ history, obj }) => { [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useColumnsDV(getSortParams); - const sortedHistory = React.useMemo(() => { - return sortData(history, sortBy, direction); - }, [history, sortBy, direction]); + const displayHistory = React.useMemo( + () => sortData([...history].reverse(), sortBy, direction), + [history, sortBy, direction], + ); + + const { + pagination, + pagedItems: pagedHistory, + itemCount, + } = useGitOpsListPagePagination({ + items: displayHistory, + namespace: obj?.metadata?.namespace, + searchParams, + }); - const rows = useRowsDV(sortedHistory, obj); + const rows = useRowsDV(pagedHistory, obj); const argoServer = useArgoServer(obj); const argoUrl = getApplicationArgoUrl(argoServer, obj); @@ -75,7 +91,9 @@ const HistoryList: React.FC = ({ history, obj }) => { rows={rows} columns={columnsDV} emptyState={empty} - isEmpty={rows.length === 0} + isEmpty={displayHistory.length === 0} + itemCount={itemCount} + pagination={pagination} />
    ); @@ -177,7 +195,7 @@ const useRowsDV = (history: ApplicationHistory[], app: ApplicationKind): DataVie }, ]); }); - return rows.reverse(); + return rows; }; const useColumnsDV = (getSortParams: (columnIndex: number) => ThProps['sort']) => { diff --git a/src/gitops/components/imageupdater/ImageUpdaterRecentUpdatesTab.tsx b/src/gitops/components/imageupdater/ImageUpdaterRecentUpdatesTab.tsx index f3c5c686a..260ffea71 100644 --- a/src/gitops/components/imageupdater/ImageUpdaterRecentUpdatesTab.tsx +++ b/src/gitops/components/imageupdater/ImageUpdaterRecentUpdatesTab.tsx @@ -15,7 +15,11 @@ import { Tbody, Td, ThProps, Tr } from '@patternfly/react-table'; import { ImageUpdaterKind, ImageUpdaterRecentUpdate } from '../../models/ImageUpdaterModel'; import { useGitOpsTranslation } from '../../utils/hooks/useGitOpsTranslation'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; type ImageUpdaterRecentUpdatesTabProps = RouteComponentProps<{ ns: string; name: string }> & { obj?: ImageUpdaterKind; @@ -32,7 +36,8 @@ const ImageUpdaterRecentUpdatesTab: React.FC [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useColumnsDV(getSortParams, t); @@ -41,7 +46,17 @@ const ImageUpdaterRecentUpdatesTab: React.FC return sortData(updates, sortBy, direction); }, [obj, sortBy, direction]); - const rows = useRowsDV(sortedUpdates); + const { + pagination, + pagedItems: pagedUpdates, + itemCount, + } = useGitOpsListPagePagination({ + items: sortedUpdates, + namespace: obj?.metadata?.namespace, + searchParams, + }); + + const rows = useRowsDV(pagedUpdates); if (!obj) { return null; @@ -74,7 +89,9 @@ const ImageUpdaterRecentUpdatesTab: React.FC rows={rows} columns={columnsDV} emptyState={empty} - isEmpty={rows.length === 0} + isEmpty={sortedUpdates.length === 0} + itemCount={itemCount} + pagination={pagination} />
    diff --git a/src/gitops/components/project/ProjectRolesTab.tsx b/src/gitops/components/project/ProjectRolesTab.tsx index a4db7ae23..4e53d577e 100644 --- a/src/gitops/components/project/ProjectRolesTab.tsx +++ b/src/gitops/components/project/ProjectRolesTab.tsx @@ -19,7 +19,11 @@ import { AppProjectKind, Role } from '../../models/AppProjectModel'; import { ArgoServer, getArgoServerForProject } from '../../utils/gitops'; import { useGitOpsTranslation } from '../../utils/hooks/useGitOpsTranslation'; import { ArgoCDLink } from '../shared/ArgoCDLink/ArgoCDLink'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; /** * Parses an Argo CD policy string and returns a formatted React element for tooltip @@ -102,13 +106,24 @@ const ProjectRolesTab: React.FC = ({ obj }) => { [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useRolesColumnsDV(getSortParams, t); const sortedRoles = React.useMemo(() => { return sortRolesData(roles, sortBy, direction); }, [roles, sortBy, direction]); - const rows = useRolesRowsDV(sortedRoles, t); + const { + pagination, + pagedItems: pagedRoles, + itemCount, + } = useGitOpsListPagePagination({ + items: sortedRoles, + namespace: obj?.metadata?.namespace, + searchParams, + }); + + const rows = useRolesRowsDV(pagedRoles, t); if (!obj) return null; @@ -142,6 +157,8 @@ const ProjectRolesTab: React.FC = ({ obj }) => { rows={rows} isEmpty={roles.length === 0} emptyState={empty} + itemCount={itemCount} + pagination={pagination} /> ); diff --git a/src/gitops/components/project/ProjectSyncWindowsTab.tsx b/src/gitops/components/project/ProjectSyncWindowsTab.tsx index 997a9ffa6..3a725e26b 100644 --- a/src/gitops/components/project/ProjectSyncWindowsTab.tsx +++ b/src/gitops/components/project/ProjectSyncWindowsTab.tsx @@ -12,7 +12,11 @@ import { AppProjectKind, SyncWindow } from '../../models/AppProjectModel'; import { ArgoServer, getArgoServerForProject } from '../../utils/gitops'; import { useGitOpsTranslation } from '../../utils/hooks/useGitOpsTranslation'; import { ArgoCDLink } from '../shared/ArgoCDLink/ArgoCDLink'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '../shared/DataView'; type ProjectSyncWindowsTabProps = RouteComponentProps<{ ns: string; name: string }> & { obj?: AppProjectKind; @@ -52,13 +56,24 @@ const ProjectSyncWindowsTab: React.FC = ({ obj }) => [], ); - const { sortBy, direction, getSortParams } = useGitOpsDataViewSort(columnSortConfig); + const { searchParams, sortBy, direction, getSortParams } = + useGitOpsDataViewSort(columnSortConfig); const columnsDV = useSyncWindowsColumnsDV(getSortParams, t); const sortedSyncWindows = React.useMemo(() => { return sortSyncWindowsData(syncWindows, sortBy, direction); }, [syncWindows, sortBy, direction]); - const rows = useSyncWindowsRowsDV(sortedSyncWindows, t); + const { + pagination, + pagedItems: pagedSyncWindows, + itemCount, + } = useGitOpsListPagePagination({ + items: sortedSyncWindows, + namespace: obj?.metadata?.namespace, + searchParams, + }); + + const rows = useSyncWindowsRowsDV(pagedSyncWindows, t); if (!obj) return null; @@ -96,6 +111,8 @@ const ProjectSyncWindowsTab: React.FC = ({ obj }) => rows={rows} isEmpty={syncWindows.length === 0} emptyState={empty} + itemCount={itemCount} + pagination={pagination} /> ); diff --git a/src/gitops/components/rollout/components/PodList/PodList.tsx b/src/gitops/components/rollout/components/PodList/PodList.tsx index 7eefea6ba..f944899f2 100644 --- a/src/gitops/components/rollout/components/PodList/PodList.tsx +++ b/src/gitops/components/rollout/components/PodList/PodList.tsx @@ -1,7 +1,11 @@ import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import { GitOpsDataViewTable, useGitOpsDataViewSort } from '@gitops/components/shared/DataView'; +import { + GitOpsDataViewTable, + useGitOpsDataViewSort, + useGitOpsListPagePagination, +} from '@gitops/components/shared/DataView'; import { PodTraffic } from '@gitops/topology/console/pod-traffic'; import { podPhase } from '@gitops/topology/console/PodsOverview'; import { PodKind } from '@gitops/topology/console/types'; @@ -447,6 +451,16 @@ export const PodList: React.FC = ({ rollout, namespace, selector } }); }, [filteredData, searchQuery]); + const { + pagination, + pagedItems: pagedPods, + itemCount, + } = useGitOpsListPagePagination({ + items: filteredBySearch, + namespace, + searchParams, + }); + const empty = ( @@ -461,7 +475,7 @@ export const PodList: React.FC = ({ rollout, namespace, selector } const isEmptyState = !loadError && filteredBySearch.length === 0; - const rows = usePodRowsDV(filteredBySearch, memResults, cpuResults, namespace); + const rows = usePodRowsDV(pagedPods, memResults, cpuResults, namespace); const topologyUrl = rollout?.metadata?.namespace ? '/topology/ns/' + @@ -490,6 +504,8 @@ export const PodList: React.FC = ({ rollout, namespace, selector } isEmpty={isEmptyState} emptyState={empty} isError={!!loadError} + itemCount={itemCount} + pagination={pagination} />
    diff --git a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts index 5df364c09..2a60a3c5d 100644 --- a/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts +++ b/src/gitops/components/shared/DataView/gitOpsDataViewPagination.test.ts @@ -1,4 +1,9 @@ -import { getGitOpsPaginationResetKey, paginateItems } from './gitOpsDataViewPagination'; +import { + getGitOpsPaginationResetKey, + GITOPS_DEFAULT_PER_PAGE, + GITOPS_PER_PAGE_OPTIONS, + paginateItems, +} from './gitOpsDataViewPagination'; describe('paginateItems', () => { const items = ['a', 'b', 'c', 'd', 'e']; @@ -83,4 +88,94 @@ describe('getGitOpsPaginationResetKey', () => { getGitOpsPaginationResetKey('argocd', labeled), ); }); + + it('resets for Application Resources list filters but not for page changes', () => { + const filtered = new URLSearchParams( + 'page=2&rowFilter-resource-sync=Synced&rowFilter-resource-kind=Deployment', + ); + const nextPage = new URLSearchParams( + 'page=4&rowFilter-resource-sync=Synced&rowFilter-resource-kind=Deployment', + ); + const otherKind = new URLSearchParams( + 'page=2&rowFilter-resource-sync=Synced&rowFilter-resource-kind=Service', + ); + + expect(getGitOpsPaginationResetKey('openshift-gitops', filtered)).toBe( + getGitOpsPaginationResetKey('openshift-gitops', nextPage), + ); + expect(getGitOpsPaginationResetKey('openshift-gitops', filtered)).not.toBe( + getGitOpsPaginationResetKey('openshift-gitops', otherKind), + ); + }); +}); + +describe('GitOps detail-tab pagination contract', () => { + it('uses Console-compatible page size defaults', () => { + expect(GITOPS_DEFAULT_PER_PAGE).toBe(50); + expect(GITOPS_PER_PAGE_OPTIONS.map((option) => option.value)).toEqual([10, 20, 50, 100]); + }); + + it('paginates AppProject roles after sort', () => { + const roles = [ + { name: 'ci-role' }, + { name: 'read-only' }, + { name: 'admin' }, + { name: 'developer' }, + ].sort((a, b) => a.name.localeCompare(b.name)); + + expect(paginateItems(roles, 1, 2).map((role) => role.name)).toEqual(['admin', 'ci-role']); + expect(paginateItems(roles, 2, 2).map((role) => role.name)).toEqual([ + 'developer', + 'read-only', + ]); + }); + + it('paginates AppProject sync windows', () => { + const windows = [ + { kind: 'allow', schedule: '0 9 * * 1-5' }, + { kind: 'deny', schedule: '0 22 * * *' }, + { kind: 'allow', schedule: '0 12 * * 6' }, + ]; + + expect(paginateItems(windows, 1, 2)).toEqual([ + { kind: 'allow', schedule: '0 9 * * 1-5' }, + { kind: 'deny', schedule: '0 22 * * *' }, + ]); + expect(paginateItems(windows, 2, 2)).toEqual([{ kind: 'allow', schedule: '0 12 * * 6' }]); + }); + + it('paginates ImageUpdater recent updates newest-first display lists', () => { + const updates = [ + { alias: 'test-nginx', newVersion: '1.17.11' }, + { alias: 'test-memcached', newVersion: '1.6.12' }, + { alias: 'test-redis', newVersion: '7.2.0' }, + ]; + + expect(paginateItems(updates, 1, 2).map((update) => update.alias)).toEqual([ + 'test-nginx', + 'test-memcached', + ]); + expect(paginateItems(updates, 2, 2).map((update) => update.alias)).toEqual(['test-redis']); + }); + + it('paginates Application history after reversing for newest-first display', () => { + const history = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; + // Default (no column sort): reverse source order, then paginate. + const displayHistory = [...history].reverse(); + + expect(paginateItems(displayHistory, 1, 2).map((entry) => entry.id)).toEqual([4, 3]); + expect(paginateItems(displayHistory, 2, 2).map((entry) => entry.id)).toEqual([2, 1]); + }); + + it('keeps an explicit sort order when paginating history (no post-sort reverse)', () => { + const sortedAsc = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; + + expect(paginateItems(sortedAsc, 1, 2).map((entry) => entry.id)).toEqual([1, 2]); + expect(paginateItems(sortedAsc, 2, 2).map((entry) => entry.id)).toEqual([3, 4]); + }); + + it('yields no rows for empty detail-tab tables (no pager expected)', () => { + expect(paginateItems([], 1, GITOPS_DEFAULT_PER_PAGE)).toEqual([]); + expect(paginateItems(undefined, 1, GITOPS_DEFAULT_PER_PAGE)).toEqual([]); + }); }); From 82eecdac2aa7b4ab1bb7685ab651547e6559201b Mon Sep 17 00:00:00 2001 From: Keith Chong Date: Thu, 20 Aug 2026 17:43:02 -0400 Subject: [PATCH 8/8] Translate and Externalize strings in the GitOps Plugin (#9408) Signed-off-by: Keith Chong --- locales/en/plugin__gitops-plugin.json | 18 +- locales/es/plugin__gitops-console-app.json | 11 + locales/es/plugin__gitops-olm.json | 5 + locales/es/plugin__gitops-plugin.json | 364 +++++++++++ locales/es/plugin__gitops-public.json | 28 + locales/fr/plugin__gitops-console-app.json | 11 + locales/fr/plugin__gitops-olm.json | 5 + locales/fr/plugin__gitops-plugin.json | 364 +++++++++++ locales/fr/plugin__gitops-public.json | 28 + locales/ja/plugin__gitops-console-app.json | 18 +- locales/ja/plugin__gitops-olm.json | 6 +- locales/ja/plugin__gitops-plugin.json | 670 ++++++++++---------- locales/ja/plugin__gitops-public.json | 46 +- locales/ko/plugin__gitops-console-app.json | 18 +- locales/ko/plugin__gitops-olm.json | 6 +- locales/ko/plugin__gitops-plugin.json | 676 ++++++++++----------- locales/ko/plugin__gitops-public.json | 48 +- locales/zh/plugin__gitops-console-app.json | 18 +- locales/zh/plugin__gitops-olm.json | 6 +- locales/zh/plugin__gitops-plugin.json | 674 ++++++++++---------- locales/zh/plugin__gitops-public.json | 50 +- 21 files changed, 1943 insertions(+), 1127 deletions(-) create mode 100644 locales/es/plugin__gitops-console-app.json create mode 100644 locales/es/plugin__gitops-olm.json create mode 100644 locales/es/plugin__gitops-plugin.json create mode 100644 locales/es/plugin__gitops-public.json create mode 100644 locales/fr/plugin__gitops-console-app.json create mode 100644 locales/fr/plugin__gitops-olm.json create mode 100644 locales/fr/plugin__gitops-plugin.json create mode 100644 locales/fr/plugin__gitops-public.json diff --git a/locales/en/plugin__gitops-plugin.json b/locales/en/plugin__gitops-plugin.json index e2bac020c..a11904d03 100644 --- a/locales/en/plugin__gitops-plugin.json +++ b/locales/en/plugin__gitops-plugin.json @@ -342,6 +342,14 @@ "Created at": "Created at", "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of", "List view": "List view", "Graph view": "Graph view", "Sync": "Sync", @@ -352,13 +360,5 @@ "You don't have permission to perform this action": "You don't have permission to perform this action", "annotations": "annotations", "annotation": "annotation", - "No owner": "No owner", - "Pagination": "Pagination", - "Go to first page": "Go to first page", - "Go to previous page": "Go to previous page", - "Go to next page": "Go to next page", - "Go to last page": "Go to last page", - "Items per page": "Items per page", - "per page": "per page", - "of": "of" + "No owner": "No owner" } diff --git a/locales/es/plugin__gitops-console-app.json b/locales/es/plugin__gitops-console-app.json new file mode 100644 index 000000000..e18f62d68 --- /dev/null +++ b/locales/es/plugin__gitops-console-app.json @@ -0,0 +1,11 @@ +{ + "Name is required.": "Se requiere el nombre.", + "Name can only contain letters, numbers, spaces, and hyphens.": "El nombre solo puede contener letras, números, espacios y guiones.", + "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "El nombre {{favoriteName}} ya existe en sus favoritos. Elija un nombre único para guardarlo en sus favoritos.", + "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "Se alcanzó la cantidad máxima de favoritos ({{maxCount}}). Para añadir otro favorito, elimine una página existente de sus favoritos.", + "Remove from favorites": "Eliminar de favoritos", + "Add to favorites": "Añadir a favoritos", + "Save": "Guardar", + "Cancel": "Cancelar", + "Name": "Nombre" +} diff --git a/locales/es/plugin__gitops-olm.json b/locales/es/plugin__gitops-olm.json new file mode 100644 index 000000000..eac1f3436 --- /dev/null +++ b/locales/es/plugin__gitops-olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Mostrar operandos en:", + "All namespaces": "Todos los espacios de nombres", + "Current namespace only": "Solo espacio de nombres actual" +} diff --git a/locales/es/plugin__gitops-plugin.json b/locales/es/plugin__gitops-plugin.json new file mode 100644 index 000000000..8350ce242 --- /dev/null +++ b/locales/es/plugin__gitops-plugin.json @@ -0,0 +1,364 @@ +{ + "Application details": "Detalles de la aplicación", + "Health Status": "Estado", + "Health status represents the overall health of the application.": "El estado representa el estado general de la aplicación.", + "Current Sync Status": "Estado de sincronización actual", + "Sync status represents the current synchronized state for the application.": "El estado de sincronización representa el estado de sincronización actual de la aplicación.", + "Last Sync Status": "Estado de la última sincronización", + "The result of the last sync status.": "El resultado del estado de la última sincronización.", + "Target Revision": "Revisión objetivo", + "The specified revision for the Application.": "La revisión especificada para la aplicación.", + "Project": "Proyecto", + "The Argo CD Project that this application belongs to.": "El proyecto Argo CD al que pertenece esta aplicación.", + "Destination": "Destino", + "The cluster and namespace where the application is targeted": "El clúster y el espacio de nombre a los que está destinada la aplicación.", + "Sync Policy": "Política de sincronización", + "Provides options to determine application synchronization behavior": "Proporciona opciones para determinar el comportamiento de sincronización de la aplicación.", + "Automated": "Automatizado", + "Prune": "Recorte", + "Self Heal": "Autorreparación", + "Sync history": "Historial de sincronización", + "Details": "Detalles", + "YAML": "YAML", + "Sources": "Fuentes", + "Resources": "Recursos", + "Sync Status": "Estado de sincronización", + "History": "Historia", + "Events": "Eventos", + "Application resources": "Recursos de aplicación", + "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "Las vistas de gráfico y tabla muestran el estado general y de la sincronización únicamente de los recursos inmediatos de la aplicación. Haga clic en el enlace de Argo CD para ver el árbol de recursos completo. Utilice el filtro para filtrar los recursos por estado y tipo.", + "No resources": "No hay recursos", + "There are no resources associated with the application.": "No hay recursos asociados a la aplicación.", + "There are no resources based on the applied filters. Adjust the filters to see more resources.": "No hay recursos basados en los filtros aplicados. Ajuste los filtros para ver más recursos.", + "Search by name...": "Buscar por nombre...", + "Name": "Nombre", + "Namespace": "Espacio de nombre", + "Sync Wave": "Ola de sincronización", + "No Sync Status": "No hay estado de sincronización", + "None": "Ninguno", + "Kind": "Tipo", + "Type": "Tipo", + "Repository": "Repositorio", + "Path / Chart": "Ruta/gráfico", + "Ref": "Referencia", + "No source": "Sin fuente", + "Error. There must at least one source in the application.": "Error. Debe haber al menos una fuente en la aplicación.", + "Application sources": "Fuentes de la aplicación", + "Sync status": "Estado de sincronización", + "Operation": "Operación", + "The operation that was performed.": "La operación que se realizó.", + "Phase": "Fase", + "The operation phase.": "La fase operativa.", + "Message": "Mensaje", + "The message from the operation.": "El mensaje de la operación.", + "Initiated By": "Iniciado por", + "Who initiated the operation.": "Quién inició la operación.", + "automated sync policy": "política de sincronización automatizada", + "Started At": "Iniciado a las", + "When the operation was started.": "Cuándo se inició la operación.", + "Duration": "Duración", + "How long the operation took to complete.": "Cuánto tiempo tardó en completarse la operación.", + "Finished At": "Finalizado a las", + "When the operation was finished.": "Cuándo terminó la operación.", + "Resources Last Synced": "Última sincronización de recursos", + "Status": "Estado", + "Hook": "Hook", + "Edit labels": "Editar etiquetas", + "Edit annotations": "Editar anotaciones", + "Delete {{x}}": "Eliminar {{x}}", + "Edit {{x}}": "Editar {{x}}", + "View in Argo CD": "Ver en Argo CD", + "View Details": "Ver detalles", + "Edit Application": "Editar aplicación", + "Delete Application": "Eliminar aplicación", + "Show {{x}}": "Mostrar {{x}}", + "Hide {{x}}": "Ocultar {{x}}", + "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Alterne entre las formas de OpenShift y las formas de Argo CD para los nodos del árbol. Configuración actual: {{x}}", + "Group resources of the same kind into one node": "Agrupe los recursos del mismo tipo en un nodo.", + "Group Nodes": "Nodos de grupo", + "There is no health status for this resource": "No hay información sobre el estado de este recurso.", + "Unknown": "Desconocido", + "Sync Unknown": "Sincronización desconocida", + "One or more resources are in Progressing state": "Uno o más recursos se encuentran en estado En curso.", + "Step {{x}}": "Paso {{x}}", + "Step: unmatched": "Paso: no coincide", + "No history": "Sin historial", + "There is no history associated with the application.": "No existe ningún historial asociado a la aplicación.", + "ID": "ID", + "Deploy Started At": "La implementación comenzó a las", + "Deployed At": "Implementado a las", + "Revision(s) and Source Repo URL(s)": "Revisiones y URL del repositorio de origen", + "ApplicationSet details": "Detalles del ApplicationSet", + "Current health status of the ApplicationSet.": "Estado actual del ApplicationSet.", + "Generated Apps": "Aplicaciones generadas", + "Number of applications generated by this ApplicationSet.": "Cantidad de aplicaciones generadas por este ApplicationSet.", + "application": "aplicación", + "applications": "aplicaciones", + "Generators": "Generadores", + "Number of generators configured in this ApplicationSet.": "Cantidad de generadores configurados en este ApplicationSet.", + "generator": "generador", + "generators": "generadores", + "App Project": "AppProject", + "Argo CD project that this ApplicationSet belongs to.": "Proyecto Argo CD al que pertenece este ApplicationSet.", + "Git repository URL where the ApplicationSet configuration is stored.": "URL del repositorio Git en el que se almacena la configuración de ApplicationSet.", + "Progressive Sync Step {{x}}": "Paso de sincronización progresiva {{x}}", + "Applications": "Aplicaciones", + "Show all match expressions": "Mostrar todas las expresiones de coincidencia", + "Edit ApplicationSet": "Editar ApplicationSet", + "Delete ApplicationSet": "Eliminar ApplicationSet", + "View Graph": "Ver gráfico", + "Match Expressions": "Expresiones de coincidencia", + "Name must be unique within a namespace.": "El nombre debe ser único dentro de un espacio de nombre.", + "AppSet ownerReference Tree View": "Vista de árbol de ownerReference de AppSet", + "Progressive Sync Flow View": "Vista del flujo de sincronización progresiva", + "Expand or collapse all progressive sync step groups": "Expandir o contraer todos los grupos de pasos de sincronización progresiva", + "No Applications In This Step": "No hay aplicaciones en este paso", + "Edit ImageUpdater": "Editar ImageUpdater", + "Delete ImageUpdater": "Eliminar ImageUpdater", + "Error: Missing required route parameters": "Error: faltan parámetros de ruta obligatorios", + "True": "Verdadero", + "False": "Falso", + "ImageUpdater details": "Detalles de ImageUpdater", + "Ready": "Listo", + "Whether the last reconciliation completed without errors.": "Indica si la última conciliación se completó sin errores.", + "Applications Matched": "Aplicaciones coincidentes", + "Number of applications matched by this ImageUpdater.": "Cantidad de aplicaciones que coinciden con este ImageUpdater.", + "Images Managed": "Imágenes gestionadas", + "Number of images eligible for update checking.": "Cantidad de imágenes aptas para la comprobación de actualizaciones.", + "Last Checked At": "Última comprobación a las", + "When the controller last checked for image updates.": "Cuándo fue la última vez que el controlador comprobó si había actualizaciones de imagen.", + "Last Updated At": "Última actualización a las", + "When the controller last performed an image update.": "Cuándo fue la última vez que el controlador realizó una actualización de imagen.", + "Observed Generation": "Generación observada", + "The generation of the resource that was last reconciled.": "La generación del recurso que se concilió por última vez.", + "Conditions": "Condiciones", + "No ImageUpdaters match the search filter": "No se encontraron ImageUpdaters que coincidan con el filtro de búsqueda.", + "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Quite el filtro o busque un término diferente para ver más ImageUpdaters.", + "There are no ImageUpdaters in this namespace.": "No hay ImageUpdaters en este espacio de nombres.", + "There are no ImageUpdaters in all namespaces.": "No hay ImageUpdaters en todos los espacios de nombre.", + "No matching ImageUpdaters": "No hay ImageUpdaters que coincidan", + "No ImageUpdaters": "Sin ImageUpdaters", + "Unable to load data": "No se pudieron cargar los datos", + "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "Se produjo un error al recuperar los ImageUpdaters. Compruebe su conexión y vuelva a cargar la página.", + "ImageUpdaters": "ImageUpdaters", + "Create ImageUpdater": "Crear ImageUpdater", + "Apps": "Aplicaciones", + "Images": "Imágenes", + "Last Checked": "Última comprobación", + "Has Apps": "Tiene aplicaciones", + "No Apps": "Sin aplicaciones", + "Not Ready": "No está listo", + "Recent Updates": "Actualizaciones recientes", + "ArgoCD ImageUpdater": "ImageUpdater de ArgoCD", + "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "Se produjo un error al recuperar el ImageUpdater. Compruebe su conexión y vuelva a cargar la página.", + "No recent updates": "No hay actualizaciones recientes", + "No image updates have been recorded in the most recent reconciliation cycle.": "No se han registrado actualizaciones de imágenes en el ciclo de conciliación más reciente.", + "Alias": "Alias", + "Image": "Imagen", + "New Version": "Nueva versión", + "Apps Updated": "Aplicaciones actualizadas", + "Updated At": "Actualizado a las", + "Server": "Servidor", + "Deny": "Denegar", + "Allow": "Permitir", + "No destinations configured": "No hay destinos configurados", + "This AppProject does not have any destinations configured.": "Este AppProject no tiene ningún destino configurado.", + "Edit AppProject": "Editar AppProject", + "Delete": "Eliminar", + "Allowed Sources": "Fuentes permitidas", + "Allowed Sources help": "Repositorios Git y espacios de nombre permitidos como fuentes para las aplicaciones en este proyecto.", + "Repositories": "Repositorios", + "Namespaces": "Espacios de nombres", + "Allowed Destinations": "Destinos permitidos", + "Allowed Destinations help": "Clústeres y espacios de nombre en los que se permite la implementación de aplicaciones en este proyecto.", + "Resource Allow/Deny Lists": "Listas de recursos permitidos/denegados", + "Resource Allow/Deny Lists help": "Listas de recursos de Kubernetes permitidos o denegados para las aplicaciones de este proyecto. Los recursos con alcance al clúster se aplican a todos los clústeres, mientras que los recursos con alcance al espacio de nombre se aplican a espacios de nombre específicos.", + "Cluster Resource Allow List": "Lista de recursos del clúster permitidos", + "Cluster Resource Deny List": "Lista de recursos del clúster denegados", + "Namespace Resource Allow List": "Lista de recursos del espacio de nombre permitidos", + "Namespace Resource Deny List": "Lista de recursos de espacio de nombre denegados", + "AppProject details": "Detalles del AppProject", + "Project Type": "Tipo de proyecto", + "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "El proyecto predeterminado se crea automáticamente y no se puede eliminar. Puede modificarse, pero se recomienda crear proyectos específicos para su uso en producción.", + "Default Project": "Proyecto predeterminado", + "Description": "Descripción", + "Description of the AppProject.": "Descripción del AppProject.", + "Number of applications using this AppProject.": "Cantidad de aplicaciones que utilizan este AppProject.", + "Destinations": "Destinos", + "Number of clusters and namespaces where applications are allowed to be deployed.": "Cantidad de clústeres y espacios de nombre en los que se permite la implementación de aplicaciones.", + "destination": "destino", + "destinations": "destinos", + "Source Repositories": "Repositorios de origen", + "Number of allowed source repositories for this AppProject.": "Cantidad de repositorios de origen permitidos para este AppProject.", + "repository": "repositorio", + "repositories": "repositorios", + "Source Namespaces": "Espacios de nombre de origen", + "Number of allowed source namespaces for this AppProject.": "Cantidad de espacios de nombre de origen permitidos para este AppProject.", + "namespace": "espacio de nombre", + "namespaces": "espacios de nombre", + "Roles": "Roles", + "Number of roles configured in this AppProject.": "Cantidad de roles configurados en este AppProject.", + "role": "rol", + "roles": "roles", + "Sync Windows": "Ventanas de sincronización", + "Number of sync windows configured in this AppProject.": "Cantidad de ventanas de sincronización configuradas en este AppProject.", + "sync window": "ventana de sincronización", + "sync windows": "ventanas de sincronización", + "Project-Scoped Clusters Only": "Solo clústeres con alcance al proyecto", + "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "Cuando está habilitada, las aplicaciones solo se pueden implementar en clústeres con alcance a este proyecto. Esto impide la implementación en clústeres que no forman parte del proyecto.", + "Enabled": "Activado", + "Disabled": "Desactivado", + "No Argo CD App Projects match the search filter": "No hay proyectos de aplicaciones de Argo CD que coincidan con el filtro de búsqueda", + "Try removing the filter or searching for a different term to see more App Projects.": "Quite el filtro o busque un término diferente para ver más proyectos de aplicaciones.", + "There are no Argo CD App Projects in this project.": "Non hay proyectos de aplicaciones de Argo CD en este proyecto.", + "There are no Argo CD App Projects in all projects.": "No hay proyectos de aplicaciones de Argo CD en todos los proyectos.", + "No matching Argo CD App Projects": "No hay proyectos de aplicaciones de Argo CD que coincidan", + "No Argo CD App Projects": "No hay proyectos de aplicaciones de Argo CD", + "There was an error retrieving App Projects. Check your connection and reload the page.": "Se produjo un error al recuperar los proyectos de aplicaciones. Compruebe su conexión y vuelva a cargar la página.", + "AppProjects": "AppProjects", + "Create AppProject": "Crear AppProject", + "Labels": "Etiquetas", + "Last Updated": "Última actualización", + "Has Description": "Tiene descripción", + "No Description": "Sin descripción", + "Has Applications": "Tiene aplicaciones", + "No Applications": "Sin aplicaciones", + "Custom Projects": "Proyectos personalizados", + "Has Source Repos": "Tiene repositorios de origen", + "No Source Repos": "Sin repositorios de origen", + "Has Destinations": "Tiene destinos", + "No Destinations": "Sin destinos", + "Allow/Deny": "Permitir/denegar", + "ArgoCD AppProject": "AppProject de ArgoCD", + "There was an error retrieving the AppProject. Check your connection and reload the page.": "Se produjo un error al recuperar el AppProject. Compruebe su conexión y vuelva a cargar la página.", + "Policy Role": "Rol", + "Policy Resource Type": "Tipo de recurso", + "Policy Permission": "Permiso", + "Policy Object": "Objeto", + "Policy Effect": "Efecto", + "No roles configured": "No hay roles configurados", + "This AppProject does not have any roles configured.": "Este AppProject no tiene ningún rol configurado.", + "Groups": "Grupos", + "Policies": "Políticas", + "No sync windows configured": "No hay ventanas de sincronización configuradas", + "This AppProject does not have any sync windows configured.": "Este AppProject no tiene configurada ninguna ventana de sincronización.", + "Schedule": "Cronograma", + "Clusters": "Clústeres", + "Manual Sync": "Sincronización manual", + "Time Zone": "Zona horaria", + "All": "Todo", + "Allowed": "Permitido", + "Denied": "Denegado", + "Group": "Grupo", + "No resources configured": "No hay recursos configurados", + "This list does not have any resources configured.": "Esta lista no tiene configurado ningún recurso.", + "Traffic": "Tráfico", + "Restarts": "Se reinicia", + "Owner": "Propietario", + "Memory": "Memoria", + "CPU": "CPU", + "Created At": "Creado a las", + "No pods": "Sin pods", + "There are no pods associated with the rollout.": "No hay pods asociados con la implementación.", + "Close": "Cerrar", + "{{x}} failed with an error.": "{{x}} falló con un error.", + "Edit Pod": "Editar pod", + "Edit Rollout": "Editar implementación", + "Promote": "Promover", + "Full Promote": "Promoción completa", + "Abort": "Abortar", + "Retry": "Reintentar", + "Restart": "Reiniciar", + "Rollback": "Revertir", + "Age": "Edad", + "Info": "Información", + "Ready containers": "Contenedores listos", + "ready": "listo", + "0 Pods": "0 pods", + "Scaling down in:": "Reducción en:", + "Rollout Revisions": "Revisiones de la implementación", + "Stable": "Estable", + "Active": "Activo", + "Preview": "Vista previa", + "Canary": "Canary", + "Rollout details": "Detalles de la implementación", + "Replicas": "Réplicas", + "The number of desired replicas for the rollout": "La cantidad de réplicas deseadas para la implementación", + "The current status of the rollout": "Estado actual de la implementación", + "There is no rollout status. Check that the Rollout Manager is created and is available.": "No hay estado de la implementación. Verifique que se haya creado el administrador de implementación y esté disponible.", + "Strategy": "Estrategia", + "Whether the rollout is using a blue-green or canary strategy": "Indica si la implementación utiliza una estrategia blue-green o canary", + "No Argo Rollouts": "Sin implementaciones de Argo", + "There are no Argo Rollouts in this project.": "No hay implementaciones de Argo en este proyecto.", + "There are no Argo Rollouts in all projects.": "No hay implementaciones de Argo en todos los proyectos.", + "There was an error retrieving rollouts. Check your connection and reload the page.": "Se produjo un error al recuperar las implementaciones. Compruebe su conexión y vuelva a cargar la página.", + "Rollouts": "Implementaciones", + "Create Rollout": "Crear implementación", + "Pods": "Pods", + "Selector": "Selector", + "Rollout Status": "Estado de implementación", + "Revisions": "Revisiones", + "There was an error retrieving the rollout. Check your connection and reload the page.": "Se produjo un error al recuperar la implementación. Compruebe su conexión y vuelva a cargar la página.", + "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "Se produjo un error al recuperar las revisiones de la implementación. Compruebe su conexión y vuelva a cargar la página.", + "Active Service": "Servicio activo", + "The active blue-green service": "El servicio blue-green activo", + "Preview Service": "Servicio de vista previa", + "The preview blue-green service": "El servicio blue-green de vista previa", + "ClusterAnalysis Template": "Plantilla de ClusterAnalysis", + "Analysis Template": "Plantilla de análisis", + "Stable Service": "Servicio estable", + "The stable service": "El servicio estable", + "Canary Service": "Servicio de canary", + "The canary service": "El servicio de canary", + "Analysis Templates": "Plantillas de análisis", + "The analysis and cluster-scoped analysis templates used for the canary strategy": "El análisis y las plantillas de análisis con alcance al clúster utilizados para la estrategia canary", + "Topology view": "Vista de topología", + "No Argo CD Applications": "Sin aplicaciones de CD Argo", + "Loading Argo CD Applications...": "Cargando aplicaciones de Argo CD…", + "No Argo CD Applications match the filter": "Ninguna aplicación de Argo CD coincide con el filtro", + "Adjust the filter to see more applications.": "Ajuste el filtro para ver más aplicaciones.", + "There are no Argo CD Applications in this application set.": "No hay aplicaciones de Argo CD en este conjunto de aplicaciones.", + "There are no Argo CD Applications in all projects.": "No hay aplicaciones de Argo CD en todos los proyectos.", + "There are no Argo CD Applications in this project.": "No hay aplicaciones de Argo CD en este proyecto.", + "There was an error retrieving applications. Check your connection and reload the page.": "Se produjo un error al recuperar las aplicaciones. Compruebe su conexión y vuelva a cargar la página.", + "ApplicationSet Applications": "Aplicaciones del ApplicationSet", + "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "Las vistas de gráfico y tabla muestran las aplicaciones del ApplicationSet. Utilice el filtro para filtrar las aplicaciones según su estado general y de sincronización.", + "Revision": "Revisión", + "No Argo CD ApplicationSets match the filter": "Ningún ApplicationSet de Argo CD coincide con el filtro", + "Adjust the filter to see more ApplicationSets.": "Ajuste el filtro para ver más ApplicationSets.", + "There are no Argo CD ApplicationSets in this project.": "Non hay ApplicationSets de Argo CD en este proyecto.", + "There are no Argo CD ApplicationSets in all projects.": "No hay ApplicationSets de Argo CD en todos los proyectos.", + "No matching Argo CD ApplicationSets": "No hay ApplicationSets de Argo CD que coincidan", + "No Argo CD ApplicationSets": "Sin ApplicationSets de Argo CD", + "There was an error retrieving applicationsets. Check your connection and reload the page.": "Se produjo un error al recuperar los applicationsets. Compruebe su conexión y vuelva a cargar la página.", + "ApplicationSets": "ApplicationSets", + "Create ApplicationSet": "Crear ApplicationSet", + "No labels": "Sin etiquetas", + "Namespace defines the space within which each name must be unique.": "El espacio de nombre define el espacio dentro del cual cada nombre debe ser único.", + "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Mapa de claves y valores de cadena que se pueden usar para organizar y categorizar (delimitar el alcance y seleccionar) objetos.", + "Edit": "Editar", + "Annotations": "Anotaciones", + "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "Las anotaciones son mapas de valores clave no estructurados que se almacenan con un recurso y que pueden configurarse mediante herramientas externas para almacenar y recuperar metadatos arbitrarios. No pueden consultarse y deben conservarse al modificar objetos.", + "Created at": "Creado en", + "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time es una envoltura de time. Tiempo que admite la serialización correcta a YAML y JSON.", + "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Las referencias del propietario vinculan este recurso con su objeto principal. Por ejemplo, las aplicaciones generadas por un ApplicationSet tendrán a ese ApplicationSet como propietario. Esta relación permite una gestión adecuada del ciclo de vida de los recursos y la recolección de basura.", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of", + "List view": "Vista de lista", + "Graph view": "Vista de gráfico", + "Sync": "Sincronización", + "Stop": "Detener", + "Refresh": "Actualizar", + "Refresh (Hard)": "Actualizar (forzada)", + "Actions": "Acciones", + "You don't have permission to perform this action": "No tiene permiso para realizar esta acción.", + "annotations": "anotaciones", + "annotation": "anotación", + "No owner": "Sin propietario" +} diff --git a/locales/es/plugin__gitops-public.json b/locales/es/plugin__gitops-public.json new file mode 100644 index 000000000..528a6d616 --- /dev/null +++ b/locales/es/plugin__gitops-public.json @@ -0,0 +1,28 @@ +{ + "Error": "Error", + "Receiving Traffic": "Recepción de tráfico", + "Not Receiving Traffic": "Sin recepción de tráfico", + "View logs": "Ver registros", + "Open URL": "Abrir URL", + "Edit": "Editar", + "Rollout": "Implementación", + "Name": "Nombre", + "Namespace": "Espacio de nombre", + "Annotations": "Anotaciones", + "No annotations": "Sin anotaciones", + "Labels": "Etiquetas", + "No labels": "Sin etiquetas", + "Update Strategy": "Estrategia de actualización", + "Replicas": "Réplicas", + "Revision History Limit": "Límite del historial de revisiones", + "True": "Verdadero", + "False": "Falso", + "Type": "Tipo", + "Status": "Estado", + "Updated": "Actualizado", + "Reason": "Razón", + "Message": "Mensaje", + "No conditions found": "No se encontraron condiciones", + "No owner": "Sin propietario", + "View {{kind}}": "Ver {{kind}}" +} diff --git a/locales/fr/plugin__gitops-console-app.json b/locales/fr/plugin__gitops-console-app.json new file mode 100644 index 000000000..ddfce9368 --- /dev/null +++ b/locales/fr/plugin__gitops-console-app.json @@ -0,0 +1,11 @@ +{ + "Name is required.": "Le nom est obligatoire.", + "Name can only contain letters, numbers, spaces, and hyphens.": "Le nom ne peut contenir que des lettres, des chiffres, des espaces et des traits d'union.", + "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "Le nom {{favoriteName}} existe déjà dans vos favoris. Choisissez un nom unique pour l'enregistrer dans vos favoris.", + "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "Nombre maximal de favoris ({{maxCount}}) atteint. Pour ajouter une autre page favorite, supprimez-en une déjà présente dans vos favoris.", + "Remove from favorites": "Supprimer des favoris", + "Add to favorites": "Ajouter aux favoris", + "Save": "Enregistrer", + "Cancel": "Annuler", + "Name": "Nom" +} diff --git a/locales/fr/plugin__gitops-olm.json b/locales/fr/plugin__gitops-olm.json new file mode 100644 index 000000000..23493964f --- /dev/null +++ b/locales/fr/plugin__gitops-olm.json @@ -0,0 +1,5 @@ +{ + "Show operands in:": "Afficher les opérandes dans :", + "All namespaces": "Tous les espaces de noms", + "Current namespace only": "Espace de noms actuel uniquement" +} diff --git a/locales/fr/plugin__gitops-plugin.json b/locales/fr/plugin__gitops-plugin.json new file mode 100644 index 000000000..7684479e0 --- /dev/null +++ b/locales/fr/plugin__gitops-plugin.json @@ -0,0 +1,364 @@ +{ + "Application details": "Détails de l'application", + "Health Status": "État de fonctionnement", + "Health status represents the overall health of the application.": "L'état de fonctionnement signifie l'état général de l'application.", + "Current Sync Status": "État de synchronisation actuel", + "Sync status represents the current synchronized state for the application.": "L'état de synchronisation représente l'état de synchronisation actuel de l'application.", + "Last Sync Status": "Dernier état de synchronisation", + "The result of the last sync status.": "Résultat de la dernière synchronisation.", + "Target Revision": "Révision des cibles", + "The specified revision for the Application.": "La révision spécifiée pour l'application.", + "Project": "Projet", + "The Argo CD Project that this application belongs to.": "Le projet Argo CD auquel appartient cette application.", + "Destination": "Destination", + "The cluster and namespace where the application is targeted": "Le cluster et l'espace de noms dans lesquels l'application est ciblée", + "Sync Policy": "Politique de synchronisation", + "Provides options to determine application synchronization behavior": "Offre des options pour déterminer le comportement de synchronisation des applications", + "Automated": "Automatisé", + "Prune": "Élaguer", + "Self Heal": "Auto-guérison", + "Sync history": "Historique de synchronisation", + "Details": "Détails", + "YAML": "YAML", + "Sources": "Sources", + "Resources": "Ressources", + "Sync Status": "Statut de sync", + "History": "Historique", + "Events": "Événements", + "Application resources": "Ressources d’application :", + "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "Les vues graphiques et tabulaires affichent uniquement l'état de santé et de synchronisation des ressources immédiates de l'application. Cliquez sur le lien du CD Argo pour afficher l'arborescence complète des ressources. Utilisez le filtre pour filtrer les ressources en fonction de leur statut et de leur type.", + "No resources": "Aucune ressource", + "There are no resources associated with the application.": "Aucune ressource n'est associée à l'application.", + "There are no resources based on the applied filters. Adjust the filters to see more resources.": "Aucune ressource ne correspond aux filtres appliqués. Ajustez les filtres pour afficher plus de ressources.", + "Search by name...": "Rechercher par nom...", + "Name": "Nom", + "Namespace": "Espace de noms", + "Sync Wave": "Sync Wave", + "No Sync Status": "État d'absence de sync", + "None": "Aucun", + "Kind": "Type", + "Type": "Type", + "Repository": "Dépôt", + "Path / Chart": "Chemin / Graphique", + "Ref": "Réf.", + "No source": "Aucune source", + "Error. There must at least one source in the application.": "Erreur. L'application doit comporter au moins une source.", + "Application sources": "Sources d'application", + "Sync status": "Statut de synchronisation", + "Operation": "Opération", + "The operation that was performed.": "L'opération qui a été effectuée.", + "Phase": "Phase", + "The operation phase.": "La phase opérationnelle.", + "Message": "Message", + "The message from the operation.": "Message de l'opération.", + "Initiated By": "Initié par", + "Who initiated the operation.": "Qui a lancé l'opération ?", + "automated sync policy": "politique de synchronisation automatisée", + "Started At": "Commencé à", + "When the operation was started.": "Lorsque l'opération a commencé.", + "Duration": "Durée", + "How long the operation took to complete.": "Combien de temps a duré l'opération ?", + "Finished At": "Terminé à", + "When the operation was finished.": "Lorsque l'opération fut terminée.", + "Resources Last Synced": "Dernière synchronisation des ressources", + "Status": "Statut", + "Hook": "Hook", + "Edit labels": "Modifier les étiquettes", + "Edit annotations": "Modifier les annotations", + "Delete {{x}}": "Supprimer {{x}}", + "Edit {{x}}": "Modifier {{x}}", + "View in Argo CD": "Voir sur le CD Argo", + "View Details": "Afficher les détails", + "Edit Application": "Modifier l'application", + "Delete Application": "Supprimer l’application", + "Show {{x}}": "Afficher {{x}}", + "Hide {{x}}": "Masquer {{x}}", + "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Basculez entre les formes OpenShift et les formes Argo CD pour les nœuds d'arbre. Paramètre actuel : {{x}}", + "Group resources of the same kind into one node": "Regroupez les ressources de même type en un seul nœud.", + "Group Nodes": "Nœuds du groupe", + "There is no health status for this resource": "L'état de santé de cette ressource n'est pas connu.", + "Unknown": "Inconnu", + "Sync Unknown": "Sync inconnue", + "One or more resources are in Progressing state": "Une ou plusieurs ressources sont en état de progression", + "Step {{x}}": "Étape {{x}}", + "Step: unmatched": "Étape : non appariée", + "No history": "Aucun historique", + "There is no history associated with the application.": "Aucune information n'est associée à cette application.", + "ID": "ID", + "Deploy Started At": "Déploiement commencé à", + "Deployed At": "Déployé à", + "Revision(s) and Source Repo URL(s)": "Révision(s) et URL(s) du dépôt source", + "ApplicationSet details": "Détails de l'ensemble d'applications", + "Current health status of the ApplicationSet.": "État de santé actuel de l'ApplicationSet.", + "Generated Apps": "Applications générées", + "Number of applications generated by this ApplicationSet.": "Nombre d'applications générées par cet ApplicationSet.", + "application": "Application :", + "applications": "Applications", + "Generators": "Générateurs", + "Number of generators configured in this ApplicationSet.": "Nombre de générateurs configurés dans cet ApplicationSet.", + "generator": "générateur", + "generators": "générateurs", + "App Project": "Projet d'application", + "Argo CD project that this ApplicationSet belongs to.": "Projet Argo CD auquel appartient cet ApplicationSet.", + "Git repository URL where the ApplicationSet configuration is stored.": "URL du dépôt Git où est stockée la configuration ApplicationSet.", + "Progressive Sync Step {{x}}": "Étape de synchronisation progressive {{x}}", + "Applications": "Applications", + "Show all match expressions": "Afficher toutes les expressions de correspondance", + "Edit ApplicationSet": "Modifier l'ensemble d'applications", + "Delete ApplicationSet": "Supprimer l’application", + "View Graph": "Afficher le graphique", + "Match Expressions": "Correspondance des expressions", + "Name must be unique within a namespace.": "Le nom doit être unique dans un espace de noms.", + "AppSet ownerReference Tree View": "Arborescence de référence du propriétaire de l'ensemble d'applications", + "Progressive Sync Flow View": "Vue du flux de synchronisation progressive", + "Expand or collapse all progressive sync step groups": "Développer ou réduire tous les groupes de pas de synchronisation progressive", + "No Applications In This Step": "Aucune candidature à cette étape", + "Edit ImageUpdater": "Modifier ImageUpdater", + "Delete ImageUpdater": "Supprimer ImageUpdater", + "Error: Missing required route parameters": "Erreur : Paramètres d'itinéraire requis manquants", + "True": "Vrai", + "False": "Faux", + "ImageUpdater details": "Détails d'ImageUpdater", + "Ready": "Prêt", + "Whether the last reconciliation completed without errors.": "Si la dernière réconciliation s'est déroulée sans erreur.", + "Applications Matched": "Applications correspondantes", + "Number of applications matched by this ImageUpdater.": "Nombre d'applications correspondantes grâce à cet ImageUpdater.", + "Images Managed": "Images gérées", + "Number of images eligible for update checking.": "Nombre d'images éligibles à la vérification des mises à jour.", + "Last Checked At": "Dernière vérification le", + "When the controller last checked for image updates.": "Quand le contrôleur a-t-il vérifié pour la dernière fois les mises à jour d'image ?", + "Last Updated At": "Heure de la dernière mise à jour", + "When the controller last performed an image update.": "Quand le contrôleur a-t-il effectué sa dernière mise à jour d'image ?", + "Observed Generation": "Génération observée", + "The generation of the resource that was last reconciled.": "La génération de la ressource qui a été réconciliée en dernier lieu.", + "Conditions": "Conditions", + "No ImageUpdaters match the search filter": "Aucun ImageUpdater ne correspond au filtre de recherche", + "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Essayez de supprimer le filtre ou de rechercher un terme différent pour voir plus d'ImageUpdaters.", + "There are no ImageUpdaters in this namespace.": "Il n'y a pas d'ImageUpdaters dans cet espace de noms.", + "There are no ImageUpdaters in all namespaces.": "Il n'existe aucun ImageUpdater dans tous les espaces de noms.", + "No matching ImageUpdaters": "Aucun modérateur d'images correspondant", + "No ImageUpdaters": "Aucun modérateur d'images", + "Unable to load data": "Impossible de charger les données", + "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des mises à jour d'images. Vérifiez votre connexion et rechargez la page.", + "ImageUpdaters": "Mise à jour des images", + "Create ImageUpdater": "Créer un outil de mise à jour d'images", + "Apps": "Applications", + "Images": "Images", + "Last Checked": "Dernière vérification", + "Has Apps": "Possède des applications", + "No Apps": "Aucune application", + "Not Ready": "Pas prêt", + "Recent Updates": "Mises à jour récentes", + "ArgoCD ImageUpdater": "ArgoCD ImageUpdater", + "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération de l'outil de mise à jour d'images. Vérifiez votre connexion et rechargez la page.", + "No recent updates": "Aucune mise à jour récente", + "No image updates have been recorded in the most recent reconciliation cycle.": "Aucune mise à jour d'image n'a été enregistrée lors du dernier cycle de réconciliation.", + "Alias": "Alias", + "Image": "Image", + "New Version": "Nouvelle version", + "Apps Updated": "Applications mises à jour", + "Updated At": "Mise à jour le", + "Server": "Serveur", + "Deny": "Refuser", + "Allow": "Autoriser", + "No destinations configured": "Aucune destination configurée", + "This AppProject does not have any destinations configured.": "Ce projet d'application ne possède aucune destination configurée.", + "Edit AppProject": "Modifier le projet d'application", + "Delete": "Supprimer", + "Allowed Sources": "Sources autorisées", + "Allowed Sources help": "Dépôts Git et espaces de noms autorisés comme sources pour les applications dans ce projet.", + "Repositories": "Dépôts", + "Namespaces": "Espaces de noms", + "Allowed Destinations": "Destinations autorisées", + "Allowed Destinations help": "Clusters et espaces de noms dans lesquels les applications de ce projet sont autorisées à être déployées.", + "Resource Allow/Deny Lists": "Listes d'autorisation/de refus des ressources", + "Resource Allow/Deny Lists help": "Listes des ressources Kubernetes autorisées ou interdites pour les applications de ce projet. Les ressources à portée de cluster s'appliquent à tous les clusters, tandis que les ressources à portée d'espace de noms s'appliquent à des espaces de noms spécifiques.", + "Cluster Resource Allow List": "Liste d'autorisation des ressources du cluster", + "Cluster Resource Deny List": "Liste de refus des ressources du cluster", + "Namespace Resource Allow List": "Liste d'autorisation des ressources d'espace de noms", + "Namespace Resource Deny List": "Liste de refus de ressources d'espace de noms", + "AppProject details": "Détails du projet App", + "Project Type": "Type de projet", + "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "Le projet par défaut est créé automatiquement et ne peut pas être supprimé. Il peut être modifié, mais il est recommandé de créer des projets dédiés pour une utilisation en production.", + "Default Project": "Projet par défaut", + "Description": "Description", + "Description of the AppProject.": "Description du projet d'application.", + "Number of applications using this AppProject.": "Nombre d'applications utilisant ce projet d'application.", + "Destinations": "Destinations", + "Number of clusters and namespaces where applications are allowed to be deployed.": "Nombre de clusters et d'espaces de noms dans lesquels le déploiement d'applications est autorisé.", + "destination": "destination", + "destinations": "destinations", + "Source Repositories": "Dépôts de sources", + "Number of allowed source repositories for this AppProject.": "Nombre de dépôts sources autorisés pour ce projet d'application.", + "repository": "dépôt", + "repositories": "dépôts", + "Source Namespaces": "Espaces de noms sources", + "Number of allowed source namespaces for this AppProject.": "Nombre d'espaces de noms sources autorisés pour ce projet d'application.", + "namespace": "espace de noms", + "namespaces": "espaces de noms", + "Roles": "Rôles", + "Number of roles configured in this AppProject.": "Nombre de rôles configurés dans ce projet d'application.", + "role": "rôle", + "roles": "rôles", + "Sync Windows": "Sync Windows", + "Number of sync windows configured in this AppProject.": "Nombre de fenêtres de synchronisation configurées dans ce projet d'application.", + "sync window": "fenêtre de synchronisation", + "sync windows": "fenêtres de synchronisation", + "Project-Scoped Clusters Only": "Groupes de projets uniquement", + "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "Lorsqu'elle est activée, cette option permet uniquement de déployer des applications sur des clusters associés à ce projet. Cela empêche le déploiement sur des clusters qui ne font pas partie du projet.", + "Enabled": "Activé", + "Disabled": "Désactivé", + "No Argo CD App Projects match the search filter": "Aucun projet d'application Argo CD ne correspond au filtre de recherche", + "Try removing the filter or searching for a different term to see more App Projects.": "Essayez de supprimer le filtre ou de rechercher un terme différent pour voir plus de projets d'applications.", + "There are no Argo CD App Projects in this project.": "Ce projet ne contient aucun projet d'application Argo CD.", + "There are no Argo CD App Projects in all projects.": "Il n'existe aucun projet d'application Argo CD dans tous les projets.", + "No matching Argo CD App Projects": "Aucun projet d'application Argo CD correspondant", + "No Argo CD App Projects": "Aucun projet d'application Argo CD", + "There was an error retrieving App Projects. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des projets d'application. Vérifiez votre connexion et rechargez la page.", + "AppProjects": "Projets d'application", + "Create AppProject": "Créer un projet d'application", + "Labels": "Étiquettes", + "Last Updated": "Dernière mise à jour", + "Has Description": "Contient une description", + "No Description": "Aucune description", + "Has Applications": "A des applications", + "No Applications": "Aucune candidature", + "Custom Projects": "Projets personnalisés", + "Has Source Repos": "Possède des dépôts sources", + "No Source Repos": "Aucun dépôt source", + "Has Destinations": "A des destinations", + "No Destinations": "Aucune destination", + "Allow/Deny": "Autoriser/Refuser", + "ArgoCD AppProject": "Projet d'application ArgoCD", + "There was an error retrieving the AppProject. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération du projet d'application. Vérifiez votre connexion et rechargez la page.", + "Policy Role": "Rôle", + "Policy Resource Type": "Type de ressource", + "Policy Permission": "Autorisation", + "Policy Object": "Objet", + "Policy Effect": "Effet", + "No roles configured": "Aucun rôle configuré", + "This AppProject does not have any roles configured.": "Ce projet d'application ne comporte aucun rôle configuré.", + "Groups": "Groupes", + "Policies": "Stratégies", + "No sync windows configured": "Aucune fenêtre de synchronisation configurée", + "This AppProject does not have any sync windows configured.": "Ce projet d'application ne possède aucune fenêtre de synchronisation configurée.", + "Schedule": "Planifier", + "Clusters": "Clusters", + "Manual Sync": "Synchronisation manuelle", + "Time Zone": "Fuseau horaire", + "All": "Tous", + "Allowed": "Autorisé", + "Denied": "Refusé", + "Group": "Groupe", + "No resources configured": "Aucune ressource configurée", + "This list does not have any resources configured.": "Cette liste ne contient aucune ressource configurée.", + "Traffic": "Trafic", + "Restarts": "Redémarre", + "Owner": "Propriétaire", + "Memory": "Mémoire", + "CPU": "Processeur", + "Created At": "Heure de création", + "No pods": "Pas de pods", + "There are no pods associated with the rollout.": "Aucun module n'est associé à ce déploiement.", + "Close": "Fermer", + "{{x}} failed with an error.": "{{x}} a échoué avec une erreur.", + "Edit Pod": "Pod de modification", + "Edit Rollout": "Déploiement de la modification", + "Promote": "Promouvoir", + "Full Promote": "Promotion complète", + "Abort": "Avorter", + "Retry": "Réessayer", + "Restart": "Redémarrage", + "Rollback": "Restaurer", + "Age": "Âge", + "Info": "Info", + "Ready containers": "Conteneurs prêts à l'emploi", + "ready": "Prêt", + "0 Pods": "0 Pods", + "Scaling down in:": "Réduction de l'échelle en :", + "Rollout Revisions": "Révisions du déploiement", + "Stable": "Stable", + "Active": "Actif", + "Preview": "Aperçu", + "Canary": "Canary", + "Rollout details": "Détails du déploiement", + "Replicas": "Réplicas", + "The number of desired replicas for the rollout": "Le nombre de répliques souhaitées pour le déploiement", + "The current status of the rollout": "État actuel du déploiement", + "There is no rollout status. Check that the Rollout Manager is created and is available.": "Aucun statut de déploiement n'est disponible. Vérifiez que le gestionnaire de déploiement est créé et disponible.", + "Strategy": "Stratégie", + "Whether the rollout is using a blue-green or canary strategy": "Que le déploiement utilise une stratégie bleu-vert ou canary", + "No Argo Rollouts": "Aucun déploiement d'Argo", + "There are no Argo Rollouts in this project.": "Aucun déploiement Argo n'est prévu dans ce projet.", + "There are no Argo Rollouts in all projects.": "Il n'y a pas de déploiement Argo dans tous les projets.", + "There was an error retrieving rollouts. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des déploiements. Vérifiez votre connexion et rechargez la page.", + "Rollouts": "Déploiements", + "Create Rollout": "Créer un déploiement", + "Pods": "Pods", + "Selector": "Sélecteur", + "Rollout Status": "État du déploiement", + "Revisions": "Révisions", + "There was an error retrieving the rollout. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération du déploiement. Vérifiez votre connexion et rechargez la page.", + "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des révisions de déploiement. Vérifiez votre connexion et rechargez la page.", + "Active Service": "Service actif", + "The active blue-green service": "Le service bleu-vert actif", + "Preview Service": "Service d'aperçu", + "The preview blue-green service": "Le service bleu-vert en avant-première", + "ClusterAnalysis Template": "Modèle d'analyse de clusters", + "Analysis Template": "Modèle d'analyse", + "Stable Service": "Service stable", + "The stable service": "Le service stable", + "Canary Service": "Service canary", + "The canary service": "Le service canary", + "Analysis Templates": "Modèles d'analyse", + "The analysis and cluster-scoped analysis templates used for the canary strategy": "Les modèles d'analyse et d'analyse par cluster utilisés pour la stratégie canary", + "Topology view": "vue topologique", + "No Argo CD Applications": "Aucune application Argo CD", + "Loading Argo CD Applications...": "Chargement des applications Argo CD...", + "No Argo CD Applications match the filter": "Aucune application Argo CD ne correspond au filtre", + "Adjust the filter to see more applications.": "Ajustez le filtre pour afficher plus d'applications.", + "There are no Argo CD Applications in this application set.": "Il n'y a pas d'applications Argo CD dans cet ensemble d'applications.", + "There are no Argo CD Applications in all projects.": "Il n'existe pas d'applications Argo CD dans tous les projets.", + "There are no Argo CD Applications in this project.": "Ce projet ne contient aucune application Argo CD.", + "There was an error retrieving applications. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des candidatures. Vérifiez votre connexion et rechargez la page.", + "ApplicationSet Applications": "Applications ApplicationSet", + "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "Les vues graphique et tabulaire affichent les applications de l'ensemble d'applications. Utilisez le filtre pour trier les applications en fonction de leur état et de leur statut de synchronisation.", + "Revision": "Révision", + "No Argo CD ApplicationSets match the filter": "Aucun ensemble d'applications Argo CD ne correspond au filtre", + "Adjust the filter to see more ApplicationSets.": "Ajustez le filtre pour afficher plus d'ensembles d'applications.", + "There are no Argo CD ApplicationSets in this project.": "Ce projet ne contient aucun ensemble d'applications Argo CD.", + "There are no Argo CD ApplicationSets in all projects.": "Il n'existe pas d'ensembles d'applications Argo CD dans tous les projets.", + "No matching Argo CD ApplicationSets": "Aucun ensemble d'applications Argo CD correspondant", + "No Argo CD ApplicationSets": "Aucun ensemble d'applications Argo CD", + "There was an error retrieving applicationsets. Check your connection and reload the page.": "Une erreur s'est produite lors de la récupération des ensembles d'applications. Vérifiez votre connexion et rechargez la page.", + "ApplicationSets": "Ensembles d'applications", + "Create ApplicationSet": "Créer une application", + "No labels": "Aucune étiquette", + "Namespace defines the space within which each name must be unique.": "L'espace de noms définit l'espace dans lequel chaque nom doit être unique.", + "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Carte des clés et des valeurs de chaîne qui peuvent être utilisées pour organiser et catégoriser (portée et sélection) des objets.", + "Edit": "Modifier", + "Annotations": "Annotations", + "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "Les annotations sont une table clé-valeur non structurée stockée avec une ressource, qui peut être configurée par des outils externes pour stocker et récupérer des métadonnées arbitraires. Elles ne sont pas interrogeables et doivent être conservées lors de la modification d'objets.", + "Created at": "Heure de création", + "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Le temps est un emballage autour du temps. Temps permettant une sérialisation correcte en YAML et JSON.", + "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Les références de propriétaire relient cette ressource à son objet parent. Par exemple, les applications générées par un ApplicationSet auront cet ApplicationSet comme propriétaire. Cette relation permet une gestion adéquate du cycle de vie des ressources et une collecte efficace des déchets.", + "Pagination": "Pagination", + "Go to first page": "Go to first page", + "Go to previous page": "Go to previous page", + "Go to next page": "Go to next page", + "Go to last page": "Go to last page", + "Items per page": "Items per page", + "per page": "per page", + "of": "of", + "List view": "Vue sous forme de liste", + "Graph view": "Vue sous forme de graphique", + "Sync": "Sync", + "Stop": "Arrêter", + "Refresh": "Actualiser", + "Refresh (Hard)": "Actualiser (difficile)", + "Actions": "Actions", + "You don't have permission to perform this action": "Vous n’êtes pas autorisé à effectuer cette action.", + "annotations": "annotations", + "annotation": "annotation", + "No owner": "Aucun propriétaire" +} diff --git a/locales/fr/plugin__gitops-public.json b/locales/fr/plugin__gitops-public.json new file mode 100644 index 000000000..0ccddbc33 --- /dev/null +++ b/locales/fr/plugin__gitops-public.json @@ -0,0 +1,28 @@ +{ + "Error": "Erreur", + "Receiving Traffic": "Réception du trafic", + "Not Receiving Traffic": "Aucune réception de trafic", + "View logs": "Afficher les journaux", + "Open URL": "Ouvrir l’URL", + "Edit": "Modifier", + "Rollout": "Rollout", + "Name": "Nom", + "Namespace": "Espace de noms", + "Annotations": "Annotations", + "No annotations": "Aucune annotation", + "Labels": "Étiquettes", + "No labels": "Aucune étiquette", + "Update Strategy": "Stratégie de mise à jour", + "Replicas": "Réplicas", + "Revision History Limit": "Limite de l'historique des révisions", + "True": "Vrai", + "False": "Faux", + "Type": "Type", + "Status": "Statut", + "Updated": "Mis à jour", + "Reason": "Motif", + "Message": "Message", + "No conditions found": "Aucune condition trouvée", + "No owner": "Aucun propriétaire", + "View {{kind}}": "Afficher {{kind}}" +} diff --git a/locales/ja/plugin__gitops-console-app.json b/locales/ja/plugin__gitops-console-app.json index 678eb48b7..4fc0fb676 100644 --- a/locales/ja/plugin__gitops-console-app.json +++ b/locales/ja/plugin__gitops-console-app.json @@ -1,11 +1,11 @@ { - "Name is required.": "Name is required.", - "Name can only contain letters, numbers, spaces, and hyphens.": "Name can only contain letters, numbers, spaces, and hyphens.", - "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.", - "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.", - "Remove from favorites": "Remove from favorites", - "Add to favorites": "Add to favorites", - "Save": "Save", - "Cancel": "Cancel", - "Name": "Name" + "Name is required.": "名前が必要です。", + "Name can only contain letters, numbers, spaces, and hyphens.": "名前には文字、数字、スペース、ハイフンのみ使用できます。", + "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "名前 {{favoriteName}} はすでにお気に入りに存在します。お気に入りに保存するには、一意の名前を選択してください。", + "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "お気に入りの最大数 ({{maxCount}}) に達しました。別のお気に入りを追加するには、既存のページをお気に入りから削除してください。", + "Remove from favorites": "「お気に入り」から削除", + "Add to favorites": "「お気に入り」に追加", + "Save": "保存", + "Cancel": "キャンセル", + "Name": "名前" } diff --git a/locales/ja/plugin__gitops-olm.json b/locales/ja/plugin__gitops-olm.json index 2345b476e..fd76dac31 100644 --- a/locales/ja/plugin__gitops-olm.json +++ b/locales/ja/plugin__gitops-olm.json @@ -1,5 +1,5 @@ { - "Show operands in:": "Show operands in:", - "All namespaces": "All namespaces", - "Current namespace only": "Current namespace only" + "Show operands in:": "以下でオペランドを表示します:", + "All namespaces": "すべての namespace", + "Current namespace only": "現在の namespace のみ" } diff --git a/locales/ja/plugin__gitops-plugin.json b/locales/ja/plugin__gitops-plugin.json index f1aeccdfc..9e39988ee 100644 --- a/locales/ja/plugin__gitops-plugin.json +++ b/locales/ja/plugin__gitops-plugin.json @@ -1,358 +1,347 @@ { - "Application details": "Application details", - "Health Status": "Health Status", - "Health status represents the overall health of the application.": "Health status represents the overall health of the application.", - "Current Sync Status": "Current Sync Status", - "Sync status represents the current synchronized state for the application.": "Sync status represents the current synchronized state for the application.", - "Last Sync Status": "Last Sync Status", - "The result of the last sync status.": "The result of the last sync status.", - "Target Revision": "Target Revision", - "The specified revision for the Application.": "The specified revision for the Application.", - "Project": "Project", - "The Argo CD Project that this application belongs to.": "The Argo CD Project that this application belongs to.", - "Destination": "Destination", - "The cluster and namespace where the application is targeted": "The cluster and namespace where the application is targeted", - "Sync Policy": "Sync Policy", - "Provides options to determine application synchronization behavior": "Provides options to determine application synchronization behavior", - "Automated": "Automated", - "Prune": "Prune", - "Self Heal": "Self Heal", - "Sync history": "Sync history", - "Details": "Details", + "Application details": "アプリケーションの詳細", + "Health Status": "健全性のステータス", + "Health status represents the overall health of the application.": "健全性のステータスは、アプリケーション全体の健全性を表します。", + "Current Sync Status": "現在の同期ステータス", + "Sync status represents the current synchronized state for the application.": "同期ステータスは、アプリケーションの現在の同期状態を表します。", + "Last Sync Status": "前回の同期ステータス", + "The result of the last sync status.": "前回の同期ステータスの結果。", + "Target Revision": "対象のリビジョン", + "The specified revision for the Application.": "アプリケーションの指定リビジョン。", + "Project": "プロジェクト", + "The Argo CD Project that this application belongs to.": "このアプリケーションが属する Argo CD プロジェクト。", + "Destination": "デプロイ先", + "The cluster and namespace where the application is targeted": "アプリケーションが対象とするクラスターと namespace", + "Sync Policy": "同期ポリシー", + "Provides options to determine application synchronization behavior": "アプリケーションの同期動作を決定するためのオプションを提供します", + "Automated": "自動化", + "Prune": "プルーン", + "Self Heal": "自動修復", + "Sync history": "同期履歴", + "Details": "詳細", "YAML": "YAML", - "Sources": "Sources", + "Sources": "ソース", "Resources": "リソース", - "Sync Status": "Sync Status", - "History": "History", - "Events": "Events", - "Application resources": "Application resources", - "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.", - "No resources": "No resources", - "There are no resources associated with the application.": "There are no resources associated with the application.", - "There are no resources based on the applied filters. Adjust the filters to see more resources.": "There are no resources based on the applied filters. Adjust the filters to see more resources.", - "Search by name...": "Search by name...", - "Name": "Name", + "Sync Status": "同期ステータス", + "History": "履歴", + "Events": "イベント", + "Application resources": "アプリケーションリソース", + "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "グラフと表形式のビューには、アプリケーションの直接のリソースの健全性と同期ステータスのみが表示されます。Argo CD リンクをクリックすると、完全なリソースツリーが表示されます。フィルターを使用して、ステータスと kind に基づいてリソースを絞り込みます。", + "No resources": "リソースなし", + "There are no resources associated with the application.": "アプリケーションに関連付けられたリソースはありません。", + "There are no resources based on the applied filters. Adjust the filters to see more resources.": "適用されたフィルターに基づくリソースはありません。フィルターを調整して、より多くのリソースを表示します。", + "Search by name...": "名前で検索...", + "Name": "名前", "Namespace": "Namespace", - "Sync Wave": "Sync Wave", - "No Sync Status": "No Sync Status", - "None": "None", - "Kind": "Kind", - "Type": "Type", - "Repository": "Repository", - "Path / Chart": "Path / Chart", - "Ref": "Ref", - "No source": "No source", - "Error. There must at least one source in the application.": "Error. There must at least one source in the application.", - "Application sources": "Application sources", - "Sync status": "Sync status", - "Operation": "Operation", - "The operation that was performed.": "The operation that was performed.", - "Phase": "Phase", - "The operation phase.": "The operation phase.", + "Sync Wave": "同期ウェーブ", + "No Sync Status": "同期ステータスなし", + "None": "なし", + "Kind": "種類", + "Type": "タイプ", + "Repository": "リポジトリー", + "Path / Chart": "パス/チャート", + "Ref": "参照", + "No source": "ソースなし", + "Error. There must at least one source in the application.": "エラー。アプリケーションには少なくとも 1 つのソースが存在する必要があります。", + "Application sources": "アプリケーションのソース", + "Sync status": "同期ステータス", + "Operation": "操作", + "The operation that was performed.": "実行された操作。", + "Phase": "フェーズ", + "The operation phase.": "操作のフェーズ。", "Message": "メッセージ", - "The message from the operation.": "The message from the operation.", - "Initiated By": "Initiated By", - "Who initiated the operation.": "Who initiated the operation.", - "automated sync policy": "automated sync policy", - "Started At": "Started At", - "When the operation was started.": "When the operation was started.", - "Duration": "Duration", - "How long the operation took to complete.": "How long the operation took to complete.", - "Finished At": "Finished At", - "When the operation was finished.": "When the operation was finished.", - "Resources Last Synced": "Resources Last Synced", - "Status": "Status", - "Hook": "Hook", - "Edit labels": "Edit labels", - "Edit annotations": "Edit annotations", - "Delete {{x}}": "Delete {{x}}", - "Edit {{x}}": "Edit {{x}}", - "View in Argo CD": "View in Argo CD", - "View Details": "View Details", - "Edit Application": "Edit Application", - "Delete Application": "Delete Application", - "Show {{x}}": "Show {{x}}", - "Hide {{x}}": "Hide {{x}}", - "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}", - "Group resources of the same kind into one node": "Group resources of the same kind into one node", - "Group Nodes": "Group Nodes", - "There is no health status for this resource": "There is no health status for this resource", + "The message from the operation.": "操作により生成されたメッセージ。", + "Initiated By": "開始者", + "Who initiated the operation.": "操作を開始したユーザー。", + "automated sync policy": "自動同期ポリシー", + "Started At": "開始日時", + "When the operation was started.": "操作を開始した時刻。", + "Duration": "期間", + "How long the operation took to complete.": "操作完了までにかかった時刻。", + "Finished At": "終了日時", + "When the operation was finished.": "操作が完了した時間。", + "Resources Last Synced": "最後に同期されたリソース", + "Status": "ステータス", + "Hook": "フック", + "Edit labels": "ラベルの編集", + "Edit annotations": "アノテーションの編集", + "Delete {{x}}": "{{x}} の削除", + "Edit {{x}}": "{{x}} の編集", + "View in Argo CD": "Argo CD での表示", + "View Details": "詳細の表示", + "Edit Application": "アプリケーションの編集", + "Delete Application": "アプリケーションの削除", + "Show {{x}}": "{{x}} の表示", + "Hide {{x}}": "{{x}} の非表示", + "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "ツリーノードの OpenShift シェイプと Argo CD シェイプを切り替えます。現在の設定: {{x}}", + "Group resources of the same kind into one node": "同じ kind のリソースを 1 つのノードにグループ化します", + "Group Nodes": "ノードのグループ化", + "There is no health status for this resource": "このリソースの健全性ステータスはありません", "Unknown": "不明", - "Sync Unknown": "Sync Unknown", - "One or more resources are in Progressing state": "One or more resources are in Progressing state", - "Step {{x}}": "Step {{x}}", - "Step: unmatched": "Step: unmatched", + "Sync Unknown": "同期が不明", + "One or more resources are in Progressing state": "1 つ以上のリソースが進行中の状態です", + "Step {{x}}": "ステップ {{x}}", + "Step: unmatched": "ステップ: 一致しません", "No history": "履歴がありません", - "There is no history associated with the application.": "There is no history associated with the application.", + "There is no history associated with the application.": "アプリケーションには関連付けられている履歴が一切ありません。", "ID": "ID", - "Deploy Started At": "Deploy Started At", - "Deployed At": "Deployed At", - "Revision(s) and Source Repo URL(s)": "Revision(s) and Source Repo URL(s)", - "ApplicationSet details": "ApplicationSet details", - "Current health status of the ApplicationSet.": "Current health status of the ApplicationSet.", - "Generated Apps": "Generated Apps", - "Number of applications generated by this ApplicationSet.": "Number of applications generated by this ApplicationSet.", - "application": "application", - "applications": "applications", - "Generators": "Generators", - "Number of generators configured in this ApplicationSet.": "Number of generators configured in this ApplicationSet.", - "generator": "generator", - "generators": "generators", + "Deploy Started At": "デプロイ開始時刻", + "Deployed At": "デプロイ先", + "Revision(s) and Source Repo URL(s)": "リビジョンおよびソースリポジトリーの URL", + "ApplicationSet details": "ApplicationSet の詳細", + "Current health status of the ApplicationSet.": "ApplicationSet の現在の健全性ステータス。", + "Generated Apps": "生成されたアプリケーション", + "Number of applications generated by this ApplicationSet.": "このアプリケーションセットによって生成されたアプリケーションの数。", + "application": "アプリケーション", + "applications": "アプリケーション", + "Generators": "ジェネレーター", + "Number of generators configured in this ApplicationSet.": "この ApplicationSet で設定されているジェネレーターの数。", + "generator": "ジェネレーター", + "generators": "ジェネレーター", "App Project": "AppProject", - "Argo CD project that this ApplicationSet belongs to.": "Argo CD project that this ApplicationSet belongs to.", - "Git repository URL where the ApplicationSet configuration is stored.": "Git repository URL where the ApplicationSet configuration is stored.", - "Progressive Sync Step {{x}}": "Progressive Sync Step {{x}}", - "Applications": "Applications", - "Show all match expressions": "Show all match expressions", - "Edit ApplicationSet": "Edit ApplicationSet", - "Delete ApplicationSet": "Delete ApplicationSet", - "View Graph": "View Graph", - "Match Expressions": "Match Expressions", - "Name must be unique within a namespace.": "Name must be unique within a namespace.", - "AppSet ownerReference Tree View": "AppSet ownerReference Tree View", - "Progressive Sync Flow View": "Progressive Sync Flow View", - "Expand or collapse all progressive sync step groups": "Expand or collapse all progressive sync step groups", - "No Applications In This Step": "No Applications In This Step", - "Edit ImageUpdater": "Edit ImageUpdater", - "Delete ImageUpdater": "Delete ImageUpdater", - "Error: Missing required route parameters": "Error: Missing required route parameters", + "Argo CD project that this ApplicationSet belongs to.": "この ApplicationSet が属する Argo CD プロジェクト。", + "Git repository URL where the ApplicationSet configuration is stored.": "ApplicationSet の設定が保存されている Git リポジトリーの URL。", + "Progressive Sync Step {{x}}": "Progressive Sync ステップ {{x}}", + "Applications": "アプリケーション", + "Show all match expressions": "すべてのマッチ式の表示", + "Edit ApplicationSet": "ApplicationSet の編集", + "Delete ApplicationSet": "ApplicationSet の削除", + "View Graph": "グラフの表示", + "Match Expressions": "一致式", + "Name must be unique within a namespace.": "名前は namespace 内で一意である必要があります。", + "AppSet ownerReference Tree View": "AppSet ownerReference ツリービュー", + "Progressive Sync Flow View": "Progressive Sync フロービュー", + "Expand or collapse all progressive sync step groups": "すべての Progressive Sync ステップグループを展開または折りたたむ", + "No Applications In This Step": "このステップにはアプリケーションはありません", + "Edit ImageUpdater": "ImageUpdater の編集", + "Delete ImageUpdater": "ImageUpdater の削除", + "Error: Missing required route parameters": "エラー: 必須のルートパラメーターがありません", "True": "True", "False": "False", - "ImageUpdater details": "ImageUpdater details", - "Ready": "Ready", - "Whether the last reconciliation completed without errors.": "Whether the last reconciliation completed without errors.", - "Applications Matched": "Applications Matched", - "Number of applications matched by this ImageUpdater.": "Number of applications matched by this ImageUpdater.", - "Images Managed": "Images Managed", - "Number of images eligible for update checking.": "Number of images eligible for update checking.", - "Last Checked At": "Last Checked At", - "When the controller last checked for image updates.": "When the controller last checked for image updates.", - "Last Updated At": "Last Updated At", - "When the controller last performed an image update.": "When the controller last performed an image update.", - "Observed Generation": "Observed Generation", - "The generation of the resource that was last reconciled.": "The generation of the resource that was last reconciled.", - "Conditions": "Conditions", - "No ImageUpdaters match the search filter": "No ImageUpdaters match the search filter", - "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Try removing the filter or searching for a different term to see more ImageUpdaters.", - "There are no ImageUpdaters in this namespace.": "There are no ImageUpdaters in this namespace.", - "There are no ImageUpdaters in all namespaces.": "There are no ImageUpdaters in all namespaces.", - "No matching ImageUpdaters": "No matching ImageUpdaters", - "No ImageUpdaters": "No ImageUpdaters", - "Unable to load data": "Unable to load data", - "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", + "ImageUpdater details": "ImageUpdater の詳細", + "Ready": "準備完了", + "Whether the last reconciliation completed without errors.": "前回のリコンシリエーションがエラーなく完了したかどうか。", + "Applications Matched": "一致したアプリケーション", + "Number of applications matched by this ImageUpdater.": "この ImageUpdater に一致したアプリケーションの数。", + "Images Managed": "管理対象イメージ", + "Number of images eligible for update checking.": "更新チェックの対象となるイメージの数。", + "Last Checked At": "最終確認日時", + "When the controller last checked for image updates.": "コントローラーが最後にイメージ更新を確認した時刻。", + "Last Updated At": "最終更新日時", + "When the controller last performed an image update.": "コントローラーが最後にイメージ更新を実行した時刻。", + "Observed Generation": "確認済みの世代", + "The generation of the resource that was last reconciled.": "最後にリコンサイルされたリソースの世代。", + "Conditions": "状態", + "No ImageUpdaters match the search filter": "検索フィルターに一致する ImageUpdater はありません", + "Try removing the filter or searching for a different term to see more ImageUpdaters.": "フィルターを解除するか、別の用語で検索して、より多くの ImageUpdater を表示します。", + "There are no ImageUpdaters in this namespace.": "この namespace には ImageUpdater がありません。", + "There are no ImageUpdaters in all namespaces.": "すべての namespace に ImageUpdater はありません。", + "No matching ImageUpdaters": "一致する ImageUpdater はありません", + "No ImageUpdaters": "ImageUpdater なし", + "Unable to load data": "データをロードできません", + "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "ImageUpdaters の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", "ImageUpdaters": "ImageUpdaters", - "Create ImageUpdater": "Create ImageUpdater", - "Apps": "Apps", - "Images": "Images", - "Last Checked": "Last Checked", - "Labels": "Labels", - "Has Apps": "Has Apps", - "No Apps": "No Apps", - "Not Ready": "Not Ready", - "Recent Updates": "Recent Updates", + "Create ImageUpdater": "ImageUpdater の作成", + "Apps": "アプリケーション", + "Images": "イメージ", + "Last Checked": "最終確認日時", + "Labels": "ラベル", + "Has Apps": "アプリケーションあり", + "No Apps": "アプリケーションなし", + "Not Ready": "準備未完了", + "Recent Updates": "最近の更新", "ArgoCD ImageUpdater": "ArgoCD ImageUpdater", - "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "There was an error retrieving the ImageUpdater. Check your connection and reload the page.", - "No recent updates": "No recent updates", - "No image updates have been recorded in the most recent reconciliation cycle.": "No image updates have been recorded in the most recent reconciliation cycle.", - "Alias": "Alias", - "Image": "Image", - "New Version": "New Version", - "Apps Updated": "Apps Updated", - "Updated At": "Updated At", - "Server": "Server", - "Deny": "Deny", - "Allow": "Allow", - "No destinations configured": "No destinations configured", - "This AppProject does not have any destinations configured.": "This AppProject does not have any destinations configured.", - "Edit AppProject": "Edit AppProject", - "Delete": "Delete", - "Allowed Sources": "Allowed Sources", - "Allowed Sources help": "Git repositories and namespaces that are allowed as sources for applications in this project.", - "Repositories": "Repositories", + "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "ImageUpdater の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "No recent updates": "最近の更新はありません", + "No image updates have been recorded in the most recent reconciliation cycle.": "直近のリコンシリエーションサイクルでは、イメージの更新は記録されていません。", + "Alias": "エイリアス", + "Image": "イメージ", + "New Version": "新バージョン", + "Apps Updated": "更新されたアプリケーション", + "Updated At": "更新日時", + "Server": "サーバー", + "Deny": "拒否", + "Allow": "許可", + "No destinations configured": "宛先が設定されていません", + "This AppProject does not have any destinations configured.": "この AppProject には、宛先が設定されていません。", + "Edit AppProject": "AppProject の編集", + "Delete": "削除", + "Allowed Sources": "許可されるソース", + "Allowed Sources help": "このプロジェクトで、アプリケーションのソースコードとして許可されている Git リポジトリーと namespace。", + "Repositories": "リポジトリー", "Namespaces": "Namespaces", - "Allowed Destinations": "Allowed Destinations", - "Allowed Destinations help": "Clusters and namespaces where applications in this project are allowed to be deployed.", - "Resource Allow/Deny Lists": "Resource Allow/Deny Lists", - "Resource Allow/Deny Lists help": "Lists of Kubernetes resources that are allowed or denied for applications in this project. Cluster-scoped resources apply to all clusters, while namespace-scoped resources apply to specific namespaces.", - "Cluster Resource Allow List": "Cluster Resource Allow List", - "Cluster Resource Deny List": "Cluster Resource Deny List", - "Namespace Resource Allow List": "Namespace Resource Allow List", - "Namespace Resource Deny List": "Namespace Resource Deny List", - "AppProject details": "AppProject details", - "Project Type": "Project Type", - "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.", - "Default Project": "Default Project", - "Description": "Description", - "Description of the AppProject.": "Description of the AppProject.", - "Number of applications using this AppProject.": "Number of applications using this AppProject.", - "Destinations": "Destinations", - "Number of clusters and namespaces where applications are allowed to be deployed.": "Number of clusters and namespaces where applications are allowed to be deployed.", - "destination": "destination", - "destinations": "destinations", - "Source Repositories": "Source Repositories", - "Number of allowed source repositories for this AppProject.": "Number of allowed source repositories for this AppProject.", - "repository": "repository", - "repositories": "repositories", - "Source Namespaces": "Source Namespaces", - "Number of allowed source namespaces for this AppProject.": "Number of allowed source namespaces for this AppProject.", + "Allowed Destinations": "許可される宛先", + "Allowed Destinations help": "このプロジェクトにおいてアプリケーションのデプロイが許可されているクラスターおよび namespace。", + "Resource Allow/Deny Lists": "リソースの許可/拒否リスト", + "Resource Allow/Deny Lists help": "このプロジェクト内のアプリケーションで許可または拒否される Kubernetes リソースのリスト。クラスタースコープのリソースはすべてのクラスターに適用されますが、namespace スコープのリソースは特定の namespace に適用されます。", + "Cluster Resource Allow List": "クラスターリソース許可リスト", + "Cluster Resource Deny List": "クラスターリソース拒否リスト", + "Namespace Resource Allow List": "namespace リソース許可リスト", + "Namespace Resource Deny List": "namespace リソース拒否リスト", + "AppProject details": "AppProject の詳細", + "Project Type": "プロジェクトの種類", + "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "デフォルトプロジェクトは自動的に作成され、削除はできません。変更は可能ですが、実稼働環境での使用には専用のプロジェクトを作成することを推奨します。", + "Default Project": "デフォルトプロジェクト", + "Description": "説明", + "Description of the AppProject.": "AppProject の説明。", + "Number of applications using this AppProject.": "この AppProject を使用しているアプリケーションの数。", + "Destinations": "宛先", + "Number of clusters and namespaces where applications are allowed to be deployed.": "アプリケーションのデプロイが許可されているクラスターおよび namespace の数。", + "destination": "宛先", + "destinations": "宛先", + "Source Repositories": "ソースリポジトリー", + "Number of allowed source repositories for this AppProject.": "この AppProject で許可されているソースリポジトリーの数。", + "repository": "リポジトリー", + "repositories": "リポジトリー", + "Source Namespaces": "ソース namespace", + "Number of allowed source namespaces for this AppProject.": "この AppProject で許可されるソース namespace の数。", "namespace": "namespace", "namespaces": "namespaces", - "Roles": "Roles", - "Number of roles configured in this AppProject.": "Number of roles configured in this AppProject.", - "role": "role", - "roles": "roles", - "Sync Windows": "Sync Windows", - "Number of sync windows configured in this AppProject.": "Number of sync windows configured in this AppProject.", - "sync window": "sync window", - "sync windows": "sync windows", - "Project-Scoped Clusters Only": "Project-Scoped Clusters Only", - "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.", - "Enabled": "Enabled", - "Disabled": "Disabled", - "No Argo CD App Projects match the search filter": "No Argo CD App Projects match the search filter", - "Try removing the filter or searching for a different term to see more App Projects.": "Try removing the filter or searching for a different term to see more App Projects.", - "There are no Argo CD App Projects in this project.": "There are no Argo CD App Projects in this project.", - "There are no Argo CD App Projects in all projects.": "There are no Argo CD App Projects in all projects.", - "No matching Argo CD App Projects": "No matching Argo CD App Projects", - "No Argo CD App Projects": "No Argo CD App Projects", - "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", + "Roles": "ロール", + "Number of roles configured in this AppProject.": "この AppProject で設定されているロールの数。", + "role": "ロール", + "roles": "ロール", + "Sync Windows": "同期ウィンドウ", + "Number of sync windows configured in this AppProject.": "この AppProject で設定されている同期ウィンドウの数。", + "sync window": "同期ウィンドウ", + "sync windows": "同期ウィンドウ", + "Project-Scoped Clusters Only": "プロジェクト範囲のクラスターのみ", + "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "有効にすると、アプリケーションはこのプロジェクト範囲のクラスターにのみデプロイできます。これにより、プロジェクトに含まれていないクラスターへのデプロイが防止されます。", + "Enabled": "有効", + "Disabled": "無効", + "No Argo CD App Projects match the search filter": "検索フィルターに一致する Argo CD App Projects はありません。", + "Try removing the filter or searching for a different term to see more App Projects.": "フィルターを解除するか、別のキーワードで検索して、より多くの App Projects を表示します。", + "There are no Argo CD App Projects in this project.": "このプロジェクトには、Argo CD App Projects は含まれていません。", + "There are no Argo CD App Projects in all projects.": "すべてのプロジェクトに Argo CD App Projects は存在しません。", + "No matching Argo CD App Projects": "一致する Argo CD App Projects はありません", + "No Argo CD App Projects": "Argo CD App Projects はありません", + "There was an error retrieving App Projects. Check your connection and reload the page.": "App Projects の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", "AppProjects": "AppProjects", - "Create AppProject": "Create AppProject", - "Last Updated": "Last Updated", - "Has Description": "Has Description", - "No Description": "No Description", - "Has Applications": "Has Applications", - "No Applications": "No Applications", - "Custom Projects": "Custom Projects", - "Has Source Repos": "Has Source Repos", - "No Source Repos": "No Source Repos", - "Has Destinations": "Has Destinations", - "No Destinations": "No Destinations", - "Allow/Deny": "Allow/Deny", + "Create AppProject": "AppProject の作成", + "Last Updated": "最終更新", + "Has Description": "説明あり", + "No Description": "説明なし", + "Has Applications": "アプリケーションあり", + "No Applications": "アプリケーションなし", + "Custom Projects": "カスタムプロジェクト", + "Has Source Repos": "ソースリポジトリーあり", + "No Source Repos": "ソースリポジトリーなし", + "Has Destinations": "宛先あり", + "No Destinations": "宛先なし", + "Allow/Deny": "許可/拒否", "ArgoCD AppProject": "ArgoCD AppProject", - "There was an error retrieving the AppProject. Check your connection and reload the page.": "There was an error retrieving the AppProject. Check your connection and reload the page.", - "Policy Role": "Policy Role", - "Policy Resource Type": "Policy Resource Type", - "Policy Permission": "Policy Permission", - "Policy Object": "Policy Object", - "Policy Effect": "Policy Effect", - "No roles configured": "No roles configured", - "This AppProject does not have any roles configured.": "This AppProject does not have any roles configured.", - "Groups": "Groups", - "Policies": "Policies", - "No sync windows configured": "No sync windows configured", - "This AppProject does not have any sync windows configured.": "This AppProject does not have any sync windows configured.", - "Schedule": "Schedule", - "Clusters": "Clusters", - "Manual Sync": "Manual Sync", - "Time Zone": "Time Zone", - "All": "All", - "Allowed": "Allowed", - "Denied": "Denied", - "Group": "Group", - "No resources configured": "No resources configured", - "This list does not have any resources configured.": "This list does not have any resources configured.", - "Traffic": "Traffic", - "Restarts": "Restarts", - "Owner": "Owner", - "Memory": "Memory", + "There was an error retrieving the AppProject. Check your connection and reload the page.": "AppProject の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "Policy Role": "Role", + "Policy Resource Type": "リソースタイプ", + "Policy Permission": "許可", + "Policy Object": "オブジェクト", + "Policy Effect": "結果", + "No roles configured": "ロールは設定されていません", + "This AppProject does not have any roles configured.": "この AppProject には、ロールが設定されていません。", + "Groups": "グループ", + "Policies": "ポリシー", + "No sync windows configured": "同期ウィンドウは設定されていません", + "This AppProject does not have any sync windows configured.": "このアプリプロジェクトには、同期ウィンドウが設定されていません。", + "Schedule": "スケジュール", + "Clusters": "クラスター", + "Manual Sync": "手動同期", + "Time Zone": "タイムゾーン", + "All": "すべて", + "Allowed": "許可", + "Denied": "拒否", + "Group": "グループ", + "No resources configured": "リソースは設定されていません", + "This list does not have any resources configured.": "このリストには、設定されたリソースがありません。", + "Traffic": "トラフィック", + "Restarts": "再起動回数", + "Owner": "オーナー", + "Memory": "メモリー", "CPU": "CPU", - "Created At": "Created At", - "No pods": "No pods", - "There are no pods associated with the rollout.": "There are no pods associated with the rollout.", - "Close": "Close", - "{{x}} failed with an error.": "{{x}} failed with an error.", - "Edit Pod": "Edit Pod", - "Edit Rollout": "Edit Rollout", - "Promote": "Promote", - "Full Promote": "Full Promote", - "Abort": "Abort", - "Retry": "Retry", - "Restart": "Restart", - "Rollback": "Rollback", - "Age": "Age", - "Info": "Info", - "Ready containers": "Ready containers", - "ready": "ready", - "0 Pods": "0 Pods", - "Scaling down in:": "Scaling down in:", - "Rollout Revisions": "Rollout Revisions", - "Stable": "Stable", - "Active": "Active", - "Preview": "Preview", - "Canary": "Canary", - "Rollout details": "Rollout details", - "Replicas": "Replicas", - "The number of desired replicas for the rollout": "The number of desired replicas for the rollout", - "The current status of the rollout": "The current status of the rollout", - "There is no rollout status. Check that the Rollout Manager is created and is available.": "There is no rollout status. Check that the Rollout Manager is created and is available.", - "Strategy": "Strategy", - "Whether the rollout is using a blue-green or canary strategy": "Whether the rollout is using a blue-green or canary strategy", - "No Argo Rollouts": "No Argo Rollouts", - "There are no Argo Rollouts in this project.": "There are no Argo Rollouts in this project.", - "There are no Argo Rollouts in all projects.": "There are no Argo Rollouts in all projects.", - "There was an error retrieving rollouts. Check your connection and reload the page.": "There was an error retrieving rollouts. Check your connection and reload the page.", - "Rollouts": "Rollouts", - "Create Rollout": "Create Rollout", - "Pods": "Pods", - "Selector": "Selector", - "Rollout Status": "Rollout Status", - "Revisions": "Revisions", - "There was an error retrieving the rollout. Check your connection and reload the page.": "There was an error retrieving the rollout. Check your connection and reload the page.", - "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "There was an error retrieving the rollout revisions. Check your connection and reload the page.", - "Active Service": "Active Service", - "The active blue-green service": "The active blue-green service", - "Preview Service": "Preview Service", - "The preview blue-green service": "The preview blue-green service", - "ClusterAnalysis Template": "ClusterAnalysis Template", - "Analysis Template": "Analysis Template", - "Stable Service": "Stable Service", - "The stable service": "The stable service", - "Canary Service": "Canary Service", - "The canary service": "The canary service", - "Analysis Templates": "Analysis Templates", - "The analysis and cluster-scoped analysis templates used for the canary strategy": "The analysis and cluster-scoped analysis templates used for the canary strategy", - "Topology view": "Topology view", - "No Argo CD Applications": "No Argo CD Applications", - "Loading Argo CD Applications...": "Loading Argo CD Applications...", - "No Argo CD Applications match the filter": "No Argo CD Applications match the filter", - "Adjust the filter to see more applications.": "Adjust the filter to see more applications.", - "There are no Argo CD Applications in this application set.": "There are no Argo CD Applications in this application set.", - "There are no Argo CD Applications in all projects.": "There are no Argo CD Applications in all projects.", - "There are no Argo CD Applications in this project.": "There are no Argo CD Applications in this project.", - "There was an error retrieving applications. Check your connection and reload the page.": "There was an error retrieving applications. Check your connection and reload the page.", - "ApplicationSet Applications": "ApplicationSet Applications", - "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.", + "Created At": "作成日時", + "No pods": "Pod なし", + "There are no pods associated with the rollout.": "ロールアウトに関連付けられた Pod はありません。", + "Close": "閉じる", + "{{x}} failed with an error.": "{{x}} はエラーで失敗しました。", + "Edit Pod": "Pod の編集", + "Edit Rollout": "ロールアウトの編集", + "Promote": "プロモート", + "Full Promote": "完全なプロモート", + "Abort": "中断", + "Retry": "再試行", + "Restart": "再起動", + "Rollback": "ロールバック", + "Age": "経過時間", + "Info": "情報", + "Ready containers": "準備済みのコンテナー", + "ready": "準備完了", + "0 Pods": "0 Pod", + "Scaling down in:": "スケールダウンまでの時間:", + "Rollout Revisions": "ロールアウトのリビジョン", + "Stable": "安定", + "Active": "アクティブ", + "Preview": "プレビュー", + "Canary": "カナリア", + "Rollout details": "ロールアウトの詳細", + "Replicas": "レプリカ", + "The number of desired replicas for the rollout": "ロールアウトに必要なレプリカの数", + "The current status of the rollout": "ロールアウトの現状", + "There is no rollout status. Check that the Rollout Manager is created and is available.": "ロールアウトのステータスは不明です。Rollout Manager が作成され、利用可能であることを確認します。", + "Strategy": "ストラテジー", + "Whether the rollout is using a blue-green or canary strategy": "ロールアウトにブルーグリーン戦略またはカナリアストラテジーが使用されているかどうか", + "No Argo Rollouts": "Argo Rollouts はありません", + "There are no Argo Rollouts in this project.": "このプロジェクトには Argo Rollouts はありません。", + "There are no Argo Rollouts in all projects.": "すべてのプロジェクトに Argo Rollouts があるわけではありません。", + "There was an error retrieving rollouts. Check your connection and reload the page.": "ロールアウトの取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "Rollouts": "ロールアウト", + "Create Rollout": "ロールアウトの作成", + "Pods": "Pod", + "Selector": "セレクター", + "Rollout Status": "ロールアウトのステータス", + "Revisions": "リビジョン", + "There was an error retrieving the rollout. Check your connection and reload the page.": "ロールアウトの取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "ロールアウトのリビジョン取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "Active Service": "アクティブなサービス", + "The active blue-green service": "アクティブな blue-green サービス", + "Preview Service": "プレビューサービス", + "The preview blue-green service": "プレビュー blue-green サービス", + "ClusterAnalysis Template": "クラスター分析テンプレート", + "Analysis Template": "分析テンプレート", + "Stable Service": "安定したサービス", + "The stable service": "安定したサービス", + "Canary Service": "カナリアサービス", + "The canary service": "カナリアサービス", + "Analysis Templates": "分析テンプレート", + "The analysis and cluster-scoped analysis templates used for the canary strategy": "カナリアストラテジーで使用される分析およびクラスター範囲分析テンプレート", + "Topology view": "トポロジービュー", + "No Argo CD Applications": "Argo CD アプリケーションなし", + "Loading Argo CD Applications...": "Argo CD アプリケーションの読み込み中 ...", + "No Argo CD Applications match the filter": "フィルターに一致する Argo CD アプリケーションはありません", + "Adjust the filter to see more applications.": "フィルターを調整して、より多くのアプリケーションを表示します。", + "There are no Argo CD Applications in this application set.": "このアプリケーションセットには、Argo CD アプリケーションは含まれていません。", + "There are no Argo CD Applications in all projects.": "すべてのプロジェクトに Argo CD アプリケーションは含まれていません。", + "There are no Argo CD Applications in this project.": "このプロジェクトには Argo CD アプリケーションは含まれていません。", + "There was an error retrieving applications. Check your connection and reload the page.": "アプリケーションの取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", + "ApplicationSet Applications": "ApplicationSet アプリケーション", + "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "グラフビューと表ビューには、ApplicationSet に含まれるアプリケーションが表示されます。フィルターを使用して、アプリケーションをその健全性や同期ステータスに基づいて絞り込むことができます。", "Revision": "リビジョン", - "No Argo CD ApplicationSets match the filter": "No Argo CD ApplicationSets match the filter", - "Adjust the filter to see more ApplicationSets.": "Adjust the filter to see more ApplicationSets.", - "There are no Argo CD ApplicationSets in this project.": "There are no Argo CD ApplicationSets in this project.", - "There are no Argo CD ApplicationSets in all projects.": "There are no Argo CD ApplicationSets in all projects.", - "No matching Argo CD ApplicationSets": "No matching Argo CD ApplicationSets", - "No Argo CD ApplicationSets": "No Argo CD ApplicationSets", - "There was an error retrieving applicationsets. Check your connection and reload the page.": "There was an error retrieving applicationsets. Check your connection and reload the page.", + "No Argo CD ApplicationSets match the filter": "フィルターに一致する Argo CD ApplicationSets はありません", + "Adjust the filter to see more ApplicationSets.": "フィルターを調整して、より多くの ApplicationSets を表示します。", + "There are no Argo CD ApplicationSets in this project.": "このプロジェクトには Argo CD ApplicationSets は存在しません。", + "There are no Argo CD ApplicationSets in all projects.": "すべてのプロジェクトに Argo CD ApplicationSets は含まれていません。", + "No matching Argo CD ApplicationSets": "一致する Argo CD ApplicationSets はありません", + "No Argo CD ApplicationSets": "Argo CD ApplicationSets なし", + "There was an error retrieving applicationsets. Check your connection and reload the page.": "applicationsets の取得中にエラーが発生しました。接続状況を確認して、ページを再読み込みしてください。", "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "Create ApplicationSet", - "No labels": "No labels", - "Namespace defines the space within which each name must be unique.": "Namespace defines the space within which each name must be unique.", - "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Map of string keys and values that can be used to organize and categorize (scope and select) objects.", - "Edit": "Edit", - "Annotations": "Annotations", - "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.", - "Created at": "Created at", - "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", - "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "List view": "List view", - "Graph view": "Graph view", - "Sync": "Sync", - "Stop": "Stop", - "Refresh": "Refresh", - "Refresh (Hard)": "Refresh (Hard)", - "Actions": "Actions", - "You don't have permission to perform this action": "You don't have permission to perform this action", - "annotations": "annotations", - "annotation": "annotation", - "No owner": "No owner", + "Create ApplicationSet": "ApplicationSet の作成", + "No labels": "ラベルがありません", + "Namespace defines the space within which each name must be unique.": "namespace は、各名前が一意である必要がある空間を定義します。", + "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "オブジェクトを整理および分類 (スコープ指定および選択) するために使用できる文字列のキー値のマップ", + "Edit": "編集", + "Annotations": "アノテーション", + "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "アノテーションは、任意のメタデータを保存および取得するために外部ツールによって設定できるリソースとともに保存される、構造化されていないキー値マップです。これらはクエリーできないため、オブジェクトを変更するときに保持する必要があります。", + "Created at": "作成日時", + "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time は time のラッパーです。YAML と JSON への正しいマーシャリングをサポートする時間。", + "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "オーナーリファレンスは、このリソースをその親オブジェクトにリンクします。たとえば、ApplicationSet によって生成されたアプリケーションは、その ApplicationSet を所有者として持つことになります。この関係により、適切なリソースライフサイクル管理とガベージコレクションが可能になります。", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", @@ -360,5 +349,16 @@ "Go to last page": "Go to last page", "Items per page": "Items per page", "per page": "per page", - "of": "of" + "of": "of", + "List view": "リストビュー", + "Graph view": "グラフビュー", + "Sync": "同期", + "Stop": "停止", + "Refresh": "更新", + "Refresh (Hard)": "更新 (ハード)", + "Actions": "アクション", + "You don't have permission to perform this action": "このアクションを実行する権限がありません", + "annotations": "アノテーション", + "annotation": "アノテーション", + "No owner": "オーナーなし" } diff --git a/locales/ja/plugin__gitops-public.json b/locales/ja/plugin__gitops-public.json index f0284a431..220daef98 100644 --- a/locales/ja/plugin__gitops-public.json +++ b/locales/ja/plugin__gitops-public.json @@ -1,28 +1,28 @@ { - "Error": "Error", - "Receiving Traffic": "Receiving Traffic", - "Not Receiving Traffic": "Not Receiving Traffic", - "View logs": "View logs", - "Open URL": "Open URL", - "Edit": "Edit", - "Rollout": "Rollout", - "Name": "Name", + "Error": "エラー", + "Receiving Traffic": "トラフィック受信中", + "Not Receiving Traffic": "トラフィックは受信していません", + "View logs": "ログの表示", + "Open URL": "URL を開く", + "Edit": "編集", + "Rollout": "ロールアウト", + "Name": "名前", "Namespace": "Namespace", - "Annotations": "Annotations", - "No annotations": "No annotations", - "Labels": "Labels", - "No labels": "No labels", - "Update Strategy": "Update Strategy", - "Replicas": "Replicas", - "Revision History Limit": "Revision History Limit", + "Annotations": "アノテーション", + "No annotations": "アノテーションなし", + "Labels": "ラベル", + "No labels": "ラベルなし", + "Update Strategy": "更新ストラテジー", + "Replicas": "レプリカ", + "Revision History Limit": "改訂履歴の制限", "True": "True", "False": "False", - "Type": "Type", - "Status": "Status", - "Updated": "Updated", - "Reason": "Reason", - "Message": "Message", - "No conditions found": "No conditions found", - "No owner": "No owner", - "View {{kind}}": "View {{kind}}" + "Type": "タイプ", + "Status": "ステータス", + "Updated": "更新", + "Reason": "理由", + "Message": "メッセージ", + "No conditions found": "条件が見つかりません", + "No owner": "オーナーなし", + "View {{kind}}": "{{kind}} の表示" } diff --git a/locales/ko/plugin__gitops-console-app.json b/locales/ko/plugin__gitops-console-app.json index 678eb48b7..f0eec48f1 100644 --- a/locales/ko/plugin__gitops-console-app.json +++ b/locales/ko/plugin__gitops-console-app.json @@ -1,11 +1,11 @@ { - "Name is required.": "Name is required.", - "Name can only contain letters, numbers, spaces, and hyphens.": "Name can only contain letters, numbers, spaces, and hyphens.", - "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.", - "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.", - "Remove from favorites": "Remove from favorites", - "Add to favorites": "Add to favorites", - "Save": "Save", - "Cancel": "Cancel", - "Name": "Name" + "Name is required.": "이름은 필수 입력 항목입니다.", + "Name can only contain letters, numbers, spaces, and hyphens.": "이름에는 문자, 숫자, 공백, 하이픈만 포함할 수 있습니다.", + "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "{{favoriteName}}이라는 이름이 이미 즐겨 찾기에 있습니다. 즐겨 찾기에 저장할 중복되지 않는 고유한 이름을 선택합니다.", + "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "즐겨찾기 최대 개수({{maxCount}})에 도달했습니다. 다른 즐겨 찾기를 추가하려면 즐겨 찾기에서 기존 페이지를 제거하세요.", + "Remove from favorites": "즐겨 찾기에서 제거", + "Add to favorites": "즐겨 찾기에 추가", + "Save": "저장", + "Cancel": "취소", + "Name": "이름" } diff --git a/locales/ko/plugin__gitops-olm.json b/locales/ko/plugin__gitops-olm.json index 2345b476e..a895218b2 100644 --- a/locales/ko/plugin__gitops-olm.json +++ b/locales/ko/plugin__gitops-olm.json @@ -1,5 +1,5 @@ { - "Show operands in:": "Show operands in:", - "All namespaces": "All namespaces", - "Current namespace only": "Current namespace only" + "Show operands in:": "피연산자 표시:", + "All namespaces": "모든 네임 스페이스", + "Current namespace only": "현재 네임스페이스만" } diff --git a/locales/ko/plugin__gitops-plugin.json b/locales/ko/plugin__gitops-plugin.json index cbe7350f0..5319036c3 100644 --- a/locales/ko/plugin__gitops-plugin.json +++ b/locales/ko/plugin__gitops-plugin.json @@ -1,358 +1,347 @@ { - "Application details": "Application details", - "Health Status": "Health Status", - "Health status represents the overall health of the application.": "Health status represents the overall health of the application.", - "Current Sync Status": "Current Sync Status", - "Sync status represents the current synchronized state for the application.": "Sync status represents the current synchronized state for the application.", - "Last Sync Status": "Last Sync Status", - "The result of the last sync status.": "The result of the last sync status.", - "Target Revision": "Target Revision", - "The specified revision for the Application.": "The specified revision for the Application.", - "Project": "Project", - "The Argo CD Project that this application belongs to.": "The Argo CD Project that this application belongs to.", - "Destination": "Destination", - "The cluster and namespace where the application is targeted": "The cluster and namespace where the application is targeted", - "Sync Policy": "Sync Policy", - "Provides options to determine application synchronization behavior": "Provides options to determine application synchronization behavior", - "Automated": "Automated", - "Prune": "Prune", - "Self Heal": "Self Heal", - "Sync history": "Sync history", - "Details": "Details", + "Application details": "애플리케이션 세부 정보", + "Health Status": "상태", + "Health status represents the overall health of the application.": "상태는 애플리케이션의 전반적인 상태를 나타냅니다.", + "Current Sync Status": "현재 동기화 상태", + "Sync status represents the current synchronized state for the application.": "동기화 상태는 애플리케이션의 현재 동기화 상태를 나타냅니다.", + "Last Sync Status": "마지막 동기화 상태", + "The result of the last sync status.": "마지막 동기화 작업의 결과입니다.", + "Target Revision": "대상 리버전", + "The specified revision for the Application.": "애플리케이션의 지정된 리버전입니다.", + "Project": "프로젝트", + "The Argo CD Project that this application belongs to.": "이 애플리케이션이 속한 Argo CD 프로젝트입니다.", + "Destination": "대상", + "The cluster and namespace where the application is targeted": "애플리케이션이 대상으로 하는 클러스터 및 네임스페이스", + "Sync Policy": "동기화 정책", + "Provides options to determine application synchronization behavior": "애플리케이션 동기화 동작을 결정하는 옵션 제공", + "Automated": "자동화됨(Automated)", + "Prune": "정리(Prune)", + "Self Heal": "자동 복구(Self Heal)", + "Sync history": "동기화 내역", + "Details": "세부 정보", "YAML": "YAML", - "Sources": "Sources", + "Sources": "소스", "Resources": "리소스", - "Sync Status": "Sync Status", - "History": "History", - "Events": "Events", - "Application resources": "Application resources", - "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.", - "No resources": "No resources", - "There are no resources associated with the application.": "There are no resources associated with the application.", - "There are no resources based on the applied filters. Adjust the filters to see more resources.": "There are no resources based on the applied filters. Adjust the filters to see more resources.", - "Search by name...": "Search by name...", - "Name": "Name", - "Namespace": "Namespace", - "Sync Wave": "Sync Wave", - "No Sync Status": "No Sync Status", - "None": "None", - "Kind": "Kind", - "Type": "Type", - "Repository": "Repository", - "Path / Chart": "Path / Chart", - "Ref": "Ref", - "No source": "No source", - "Error. There must at least one source in the application.": "Error. There must at least one source in the application.", - "Application sources": "Application sources", - "Sync status": "Sync status", - "Operation": "Operation", - "The operation that was performed.": "The operation that was performed.", - "Phase": "Phase", - "The operation phase.": "The operation phase.", + "Sync Status": "동기화 상태", + "History": "내역", + "Events": "이벤트", + "Application resources": "애플리케이션 리소스", + "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "그래프 및 테이블 보기는 애플리케이션의 직접적인 리소스에 대한 상태 및 동기화 상태만 표시합니다. Argo CD 링크를 클릭하여 전체 리소스 트리를 확인합니다. 필터를 사용하여 상태 및 종류에 따라 리소스를 필터링합니다.", + "No resources": "리소스 없음", + "There are no resources associated with the application.": "애플리케이션과 연결된 리소스가 없습니다.", + "There are no resources based on the applied filters. Adjust the filters to see more resources.": "적용된 필터를 기반으로 하는 리소스가 없습니다. 더 많은 리소스를 확인하려면 필터를 조정합니다.", + "Search by name...": "이름으로 검색 ...", + "Name": "이름", + "Namespace": "네임 스페이스", + "Sync Wave": "동기화 웨이브(Sync Wave)", + "No Sync Status": "동기화 상태 없음", + "None": "없음", + "Kind": "종류", + "Type": "유형", + "Repository": "리포지토리", + "Path / Chart": "경로 / 차트", + "Ref": "참조", + "No source": "소스 없음", + "Error. There must at least one source in the application.": "오류 애플리케이션에는 하나 이상의 소스가 있어야 합니다.", + "Application sources": "애플리케이션 소스", + "Sync status": "동기화 상태", + "Operation": "작업", + "The operation that was performed.": "수행된 작업입니다.", + "Phase": "단계", + "The operation phase.": "작업 단계입니다.", "Message": "메시지", - "The message from the operation.": "The message from the operation.", - "Initiated By": "Initiated By", - "Who initiated the operation.": "Who initiated the operation.", - "automated sync policy": "automated sync policy", - "Started At": "Started At", - "When the operation was started.": "When the operation was started.", - "Duration": "Duration", - "How long the operation took to complete.": "How long the operation took to complete.", - "Finished At": "Finished At", - "When the operation was finished.": "When the operation was finished.", - "Resources Last Synced": "Resources Last Synced", - "Status": "Status", + "The message from the operation.": "작업의 메시지입니다.", + "Initiated By": "시작한 사용자", + "Who initiated the operation.": "작업을 시작한 사용자입니다.", + "automated sync policy": "자동 동기화 정책", + "Started At": "시작 시간", + "When the operation was started.": "작업이 시작된 시간입니다.", + "Duration": "소요 기간", + "How long the operation took to complete.": "작업을 완료하는 데 걸린 시간입니다.", + "Finished At": "완료 시간", + "When the operation was finished.": "작업이 완료된 시간입니다.", + "Resources Last Synced": "마지막으로 동기화된 리소스", + "Status": "상태", "Hook": "Hook", - "Edit labels": "Edit labels", - "Edit annotations": "Edit annotations", - "Delete {{x}}": "Delete {{x}}", - "Edit {{x}}": "Edit {{x}}", - "View in Argo CD": "View in Argo CD", - "View Details": "View Details", - "Edit Application": "Edit Application", - "Delete Application": "Delete Application", - "Show {{x}}": "Show {{x}}", - "Hide {{x}}": "Hide {{x}}", - "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}", - "Group resources of the same kind into one node": "Group resources of the same kind into one node", - "Group Nodes": "Group Nodes", - "There is no health status for this resource": "There is no health status for this resource", + "Edit labels": "레이블 편집", + "Edit annotations": "주석 편집", + "Delete {{x}}": "{{x}} 삭제", + "Edit {{x}}": "{{x}} 편집", + "View in Argo CD": "Argo CD에서 보기", + "View Details": "세부 정보보기", + "Edit Application": "애플리케이션 편집", + "Delete Application": "애플리케이션 삭제", + "Show {{x}}": "{{x}} 표시", + "Hide {{x}}": "{{x}} 숨기기", + "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "트리 노드에 OpenShift 형태와 Argo CD 형태 간 전환합니다. 현재 설정: {{x}}", + "Group resources of the same kind into one node": "동일한 종류의 리소스를 하나의 노드로 그룹화", + "Group Nodes": "노드 그룹화", + "There is no health status for this resource": "이 리소스에 대한 상태가 없습니다.", "Unknown": "알 수 없음", - "Sync Unknown": "Sync Unknown", - "One or more resources are in Progressing state": "One or more resources are in Progressing state", - "Step {{x}}": "Step {{x}}", - "Step: unmatched": "Step: unmatched", + "Sync Unknown": "동기화 상태 알 수 없음", + "One or more resources are in Progressing state": "하나 이상의 리소스가 진행 중(Progressing) 상태", + "Step {{x}}": "단계 {{x}}", + "Step: unmatched": "단계: 일치하지 않음", "No history": "기록 없음", - "There is no history associated with the application.": "There is no history associated with the application.", + "There is no history associated with the application.": "애플리케이션과 연결된 기록이 없습니다.", "ID": "ID", - "Deploy Started At": "Deploy Started At", - "Deployed At": "Deployed At", - "Revision(s) and Source Repo URL(s)": "Revision(s) and Source Repo URL(s)", - "ApplicationSet details": "ApplicationSet details", - "Current health status of the ApplicationSet.": "Current health status of the ApplicationSet.", - "Generated Apps": "Generated Apps", - "Number of applications generated by this ApplicationSet.": "Number of applications generated by this ApplicationSet.", - "application": "application", - "applications": "applications", - "Generators": "Generators", - "Number of generators configured in this ApplicationSet.": "Number of generators configured in this ApplicationSet.", - "generator": "generator", - "generators": "generators", - "App Project": "App Project", - "Argo CD project that this ApplicationSet belongs to.": "Argo CD project that this ApplicationSet belongs to.", - "Git repository URL where the ApplicationSet configuration is stored.": "Git repository URL where the ApplicationSet configuration is stored.", - "Progressive Sync Step {{x}}": "Progressive Sync Step {{x}}", - "Applications": "Applications", - "Show all match expressions": "Show all match expressions", - "Edit ApplicationSet": "Edit ApplicationSet", - "Delete ApplicationSet": "Delete ApplicationSet", - "View Graph": "View Graph", - "Match Expressions": "Match Expressions", - "Name must be unique within a namespace.": "Name must be unique within a namespace.", - "AppSet ownerReference Tree View": "AppSet ownerReference Tree View", - "Progressive Sync Flow View": "Progressive Sync Flow View", - "Expand or collapse all progressive sync step groups": "Expand or collapse all progressive sync step groups", - "No Applications In This Step": "No Applications In This Step", - "Edit ImageUpdater": "Edit ImageUpdater", - "Delete ImageUpdater": "Delete ImageUpdater", - "Error: Missing required route parameters": "Error: Missing required route parameters", + "Deploy Started At": "배포 시작 시간", + "Deployed At": "배포 완료 시간", + "Revision(s) and Source Repo URL(s)": "리비전 및 소스 리포지토리 URL", + "ApplicationSet details": "ApplicationSet 세부 정보", + "Current health status of the ApplicationSet.": "ApplicationSet의 현재 상태입니다.", + "Generated Apps": "생성된 애플리케이션", + "Number of applications generated by this ApplicationSet.": "이 ApplicationSet에서 생성한 애플리케이션 수입니다.", + "application": "애플리케이션", + "applications": "애플리케이션", + "Generators": "생성기", + "Number of generators configured in this ApplicationSet.": "이 ApplicationSet에 구성된 생성기 수입니다.", + "generator": "생성기", + "generators": "생성기", + "App Project": "AppProject", + "Argo CD project that this ApplicationSet belongs to.": "이 ApplicationSet이 속한 Argo CD 프로젝트입니다.", + "Git repository URL where the ApplicationSet configuration is stored.": "ApplicationSet 구성이 저장되는 Git 리포지토리 URL입니다.", + "Progressive Sync Step {{x}}": "점진적 동기화 단계 {{x}}", + "Applications": "애플리케이션", + "Show all match expressions": "모든 일치 표현식 표시", + "Edit ApplicationSet": "ApplicationSet 편집", + "Delete ApplicationSet": "ApplicationSet 삭제", + "View Graph": "그래프 보기", + "Match Expressions": "표현식 일치", + "Name must be unique within a namespace.": "이름은 네임스페이스에서 고유해야 합니다.", + "AppSet ownerReference Tree View": "AppSet ownerReference 트리 뷰", + "Progressive Sync Flow View": "단계별 동기화 프로세스 보기", + "Expand or collapse all progressive sync step groups": "모든 단계별 동기화 단계 그룹을 펼치기 또는 접기", + "No Applications In This Step": "이 단계에 애플리케이션 없음", + "Edit ImageUpdater": "ImageUpdater 편집", + "Delete ImageUpdater": "ImageUpdater 삭제", + "Error: Missing required route parameters": "오류: 필수 라우팅 매개변수가 누락되었습니다.", "True": "True", "False": "False", - "ImageUpdater details": "ImageUpdater details", - "Ready": "Ready", - "Whether the last reconciliation completed without errors.": "Whether the last reconciliation completed without errors.", - "Applications Matched": "Applications Matched", - "Number of applications matched by this ImageUpdater.": "Number of applications matched by this ImageUpdater.", - "Images Managed": "Images Managed", - "Number of images eligible for update checking.": "Number of images eligible for update checking.", - "Last Checked At": "Last Checked At", - "When the controller last checked for image updates.": "When the controller last checked for image updates.", - "Last Updated At": "Last Updated At", - "When the controller last performed an image update.": "When the controller last performed an image update.", - "Observed Generation": "Observed Generation", - "The generation of the resource that was last reconciled.": "The generation of the resource that was last reconciled.", - "Conditions": "Conditions", - "No ImageUpdaters match the search filter": "No ImageUpdaters match the search filter", - "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Try removing the filter or searching for a different term to see more ImageUpdaters.", - "There are no ImageUpdaters in this namespace.": "There are no ImageUpdaters in this namespace.", - "There are no ImageUpdaters in all namespaces.": "There are no ImageUpdaters in all namespaces.", - "No matching ImageUpdaters": "No matching ImageUpdaters", - "No ImageUpdaters": "No ImageUpdaters", - "Unable to load data": "Unable to load data", - "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", + "ImageUpdater details": "ImageUpdater 세부 정보", + "Ready": "준비 완료", + "Whether the last reconciliation completed without errors.": "마지막 조정이 오류 없이 완료되었는지 여부를 나타냅니다.", + "Applications Matched": "일치하는 애플리케이션", + "Number of applications matched by this ImageUpdater.": "이 ImageUpdater와 일치하는 애플리케이션 수입니다.", + "Images Managed": "관리되는 이미지", + "Number of images eligible for update checking.": "업데이트 확인 대상인 이미지 수입니다.", + "Last Checked At": "마지막 확인 시간", + "When the controller last checked for image updates.": "컨트롤러가 마지막으로 이미지 업데이트를 확인한 시간입니다.", + "Last Updated At": "마지막 업데이트 시간", + "When the controller last performed an image update.": "컨트롤러가 마지막으로 이미지 업데이트를 수행한 시간입니다.", + "Observed Generation": "관찰된 생성 버전", + "The generation of the resource that was last reconciled.": "마지막으로 조정된 리소스의 생성 버전입니다.", + "Conditions": "조건", + "No ImageUpdaters match the search filter": "검색 필터와 일치하는 ImageUpdater가 없음", + "Try removing the filter or searching for a different term to see more ImageUpdaters.": "더 많은 ImageUpdaters를 보려면 필터를 제거하거나 다른 용어를 검색하십시오.", + "There are no ImageUpdaters in this namespace.": "이 네임스페이스에는 ImageUpdaters가 없습니다.", + "There are no ImageUpdaters in all namespaces.": "모든 네임스페이스에 ImageUpdaters가 없습니다.", + "No matching ImageUpdaters": "일치하는 ImageUpdaters 없음", + "No ImageUpdaters": "ImageUpdaters 없음", + "Unable to load data": "데이터를 불러올 수 없음", + "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "ImageUpdaters를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", "ImageUpdaters": "ImageUpdaters", - "Create ImageUpdater": "Create ImageUpdater", - "Apps": "Apps", - "Images": "Images", - "Last Checked": "Last Checked", - "Labels": "Labels", - "Has Apps": "Has Apps", - "No Apps": "No Apps", - "Not Ready": "Not Ready", - "Recent Updates": "Recent Updates", + "Create ImageUpdater": "ImageUpdater 만들기", + "Apps": "애플리케이션", + "Images": "이미지", + "Last Checked": "마지막 확인 시간", + "Labels": "레이블", + "Has Apps": "애플리케이션 있음", + "No Apps": "애플리케이션 없음", + "Not Ready": "준비되지 않음", + "Recent Updates": "최근 업데이트", "ArgoCD ImageUpdater": "ArgoCD ImageUpdater", - "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "There was an error retrieving the ImageUpdater. Check your connection and reload the page.", - "No recent updates": "No recent updates", - "No image updates have been recorded in the most recent reconciliation cycle.": "No image updates have been recorded in the most recent reconciliation cycle.", - "Alias": "Alias", - "Image": "Image", - "New Version": "New Version", - "Apps Updated": "Apps Updated", - "Updated At": "Updated At", - "Server": "Server", - "Deny": "Deny", - "Allow": "Allow", - "No destinations configured": "No destinations configured", - "This AppProject does not have any destinations configured.": "This AppProject does not have any destinations configured.", - "Edit AppProject": "Edit AppProject", - "Delete": "Delete", - "Allowed Sources": "Allowed Sources", - "Allowed Sources help": "Git repositories and namespaces that are allowed as sources for applications in this project.", - "Repositories": "Repositories", - "Namespaces": "Namespaces", - "Allowed Destinations": "Allowed Destinations", - "Allowed Destinations help": "Clusters and namespaces where applications in this project are allowed to be deployed.", - "Resource Allow/Deny Lists": "Resource Allow/Deny Lists", - "Resource Allow/Deny Lists help": "Lists of Kubernetes resources that are allowed or denied for applications in this project. Cluster-scoped resources apply to all clusters, while namespace-scoped resources apply to specific namespaces.", - "Cluster Resource Allow List": "Cluster Resource Allow List", - "Cluster Resource Deny List": "Cluster Resource Deny List", - "Namespace Resource Allow List": "Namespace Resource Allow List", - "Namespace Resource Deny List": "Namespace Resource Deny List", - "AppProject details": "AppProject details", - "Project Type": "Project Type", - "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.", - "Default Project": "Default Project", - "Description": "Description", - "Description of the AppProject.": "Description of the AppProject.", - "Number of applications using this AppProject.": "Number of applications using this AppProject.", - "Destinations": "Destinations", - "Number of clusters and namespaces where applications are allowed to be deployed.": "Number of clusters and namespaces where applications are allowed to be deployed.", - "destination": "destination", - "destinations": "destinations", - "Source Repositories": "Source Repositories", - "Number of allowed source repositories for this AppProject.": "Number of allowed source repositories for this AppProject.", - "repository": "repository", - "repositories": "repositories", - "Source Namespaces": "Source Namespaces", - "Number of allowed source namespaces for this AppProject.": "Number of allowed source namespaces for this AppProject.", - "namespace": "namespace", - "namespaces": "namespaces", - "Roles": "Roles", - "Number of roles configured in this AppProject.": "Number of roles configured in this AppProject.", - "role": "role", - "roles": "roles", - "Sync Windows": "Sync Windows", - "Number of sync windows configured in this AppProject.": "Number of sync windows configured in this AppProject.", - "sync window": "sync window", - "sync windows": "sync windows", - "Project-Scoped Clusters Only": "Project-Scoped Clusters Only", - "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.", - "Enabled": "Enabled", - "Disabled": "Disabled", - "No Argo CD App Projects match the search filter": "No Argo CD App Projects match the search filter", - "Try removing the filter or searching for a different term to see more App Projects.": "Try removing the filter or searching for a different term to see more App Projects.", - "There are no Argo CD App Projects in this project.": "There are no Argo CD App Projects in this project.", - "There are no Argo CD App Projects in all projects.": "There are no Argo CD App Projects in all projects.", - "No matching Argo CD App Projects": "No matching Argo CD App Projects", - "No Argo CD App Projects": "No Argo CD App Projects", - "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", + "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "ImageUpdater를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "No recent updates": "최근 업데이트 없음", + "No image updates have been recorded in the most recent reconciliation cycle.": "최신 조정 주기에 이미지 업데이트가 기록되지 않았습니다.", + "Alias": "별칭", + "Image": "이미지", + "New Version": "새 버전", + "Apps Updated": "업데이트된 애플리케이션", + "Updated At": "업데이트 시간", + "Server": "서버", + "Deny": "거부", + "Allow": "허용", + "No destinations configured": "구성된 대상 없음", + "This AppProject does not have any destinations configured.": "이 AppProject에는 구성된 대상이 없습니다.", + "Edit AppProject": "AppProject 편집", + "Delete": "삭제", + "Allowed Sources": "허용된 소스", + "Allowed Sources help": "이 프로젝트의 애플리케이션에서 소스로 사용할 수 있도록 허용된 Git 리포지토리 및 네임스페이스입니다.", + "Repositories": "리포지토리", + "Namespaces": "네임스페이스", + "Allowed Destinations": "허용된 대상", + "Allowed Destinations help": "이 프로젝트의 애플리케이션을 배포할 수 있는 클러스터 및 네임스페이스입니다.", + "Resource Allow/Deny Lists": "리소스 허용/거부 목록", + "Resource Allow/Deny Lists help": "이 프로젝트의 애플리케이션에 허용되거나 거부된 Kubernetes 리소스 목록입니다. 클러스터 범위 리소스는 모든 클러스터에 적용되지만 네임스페이스 범위 리소스는 특정 네임스페이스에 적용됩니다.", + "Cluster Resource Allow List": "클러스터 리소스 허용 목록", + "Cluster Resource Deny List": "클러스터 리소스 거부 목록", + "Namespace Resource Allow List": "네임스페이스 리소스 허용 목록", + "Namespace Resource Deny List": "네임스페이스 리소스 거부 목록", + "AppProject details": "AppProject 세부 정보", + "Project Type": "프로젝트 유형", + "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "기본 프로젝트는 자동으로 생성되며 삭제할 수 없습니다. 해당 항목은 수정할 수 있지만 프로덕션 환경에서는 전용 프로젝트를 생성하는 것이 좋습니다.", + "Default Project": "기본 프로젝트", + "Description": "설명", + "Description of the AppProject.": "AppProject에 대한 설명입니다.", + "Number of applications using this AppProject.": "이 AppProject를 사용하는 애플리케이션 수입니다.", + "Destinations": "대상", + "Number of clusters and namespaces where applications are allowed to be deployed.": "애플리케이션을 배포할 수 있는 클러스터 및 네임스페이스 수입니다.", + "destination": "대상", + "destinations": "대상", + "Source Repositories": "소스 리포지토리", + "Number of allowed source repositories for this AppProject.": "이 AppProject에 허용된 소스 리포지토리 수입니다.", + "repository": "리포지토리", + "repositories": "리포지토리", + "Source Namespaces": "소스 네임스페이스", + "Number of allowed source namespaces for this AppProject.": "AppProject에 허용된 소스 네임스페이스 수입니다.", + "namespace": "네임 스페이스", + "namespaces": "네임 스페이스", + "Roles": "역할", + "Number of roles configured in this AppProject.": "이 AppProject에 구성된 역할 수입니다.", + "role": "역할", + "roles": "역할", + "Sync Windows": "동기화 창", + "Number of sync windows configured in this AppProject.": "이 AppProject에 구성된 동기화 창 수입니다.", + "sync window": "동기화 창", + "sync windows": "동기화 창", + "Project-Scoped Clusters Only": "프로젝트 범위의 클러스터만 해당", + "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "이 옵션을 활성화하면 애플리케이션을 이 프로젝트로 범위가 지정된 클러스터에만 배포할 수 있습니다. 이렇게 하면 프로젝트에 포함되지 않은 클러스터에 배포하는 것을 방지합니다.", + "Enabled": "활성화됨", + "Disabled": "비활성화됨", + "No Argo CD App Projects match the search filter": "검색 필터와 일치하는 Argo CD AppProject가 없음", + "Try removing the filter or searching for a different term to see more App Projects.": "더 많은 AppProject를 확인하려면 필터를 제거하거나 다른 용어로 검색해 보십시오.", + "There are no Argo CD App Projects in this project.": "이 프로젝트에 Argo CD AppProject가 없습니다.", + "There are no Argo CD App Projects in all projects.": "모든 프로젝트에 Argo CD AppProject가 없습니다.", + "No matching Argo CD App Projects": "일치하는 Argo CD AppProject가 없음", + "No Argo CD App Projects": "Argo CD AppProject가 없음", + "There was an error retrieving App Projects. Check your connection and reload the page.": "AppProject를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", "AppProjects": "AppProjects", - "Create AppProject": "Create AppProject", - "Last Updated": "Last Updated", - "Has Description": "Has Description", - "No Description": "No Description", - "Has Applications": "Has Applications", - "No Applications": "No Applications", - "Custom Projects": "Custom Projects", - "Has Source Repos": "Has Source Repos", - "No Source Repos": "No Source Repos", - "Has Destinations": "Has Destinations", - "No Destinations": "No Destinations", - "Allow/Deny": "Allow/Deny", + "Create AppProject": "AppProject 생성", + "Last Updated": "마지막 업데이트 시간", + "Has Description": "설명 있음", + "No Description": "설명 없음", + "Has Applications": "애플리케이션 있음", + "No Applications": "애플리케이션 없음", + "Custom Projects": "사용자 지정 프로젝트", + "Has Source Repos": "소스 리포지토리 있음", + "No Source Repos": "소스 리포지토리 없음", + "Has Destinations": "대상 있음", + "No Destinations": "대상 없음", + "Allow/Deny": "허용/거부", "ArgoCD AppProject": "ArgoCD AppProject", - "There was an error retrieving the AppProject. Check your connection and reload the page.": "There was an error retrieving the AppProject. Check your connection and reload the page.", - "Policy Role": "Policy Role", - "Policy Resource Type": "Policy Resource Type", - "Policy Permission": "Policy Permission", - "Policy Object": "Policy Object", - "Policy Effect": "Policy Effect", - "No roles configured": "No roles configured", - "This AppProject does not have any roles configured.": "This AppProject does not have any roles configured.", - "Groups": "Groups", - "Policies": "Policies", - "No sync windows configured": "No sync windows configured", - "This AppProject does not have any sync windows configured.": "This AppProject does not have any sync windows configured.", - "Schedule": "Schedule", - "Clusters": "Clusters", - "Manual Sync": "Manual Sync", - "Time Zone": "Time Zone", - "All": "All", - "Allowed": "Allowed", - "Denied": "Denied", - "Group": "Group", - "No resources configured": "No resources configured", - "This list does not have any resources configured.": "This list does not have any resources configured.", - "Traffic": "Traffic", - "Restarts": "Restarts", - "Owner": "Owner", - "Memory": "Memory", + "There was an error retrieving the AppProject. Check your connection and reload the page.": "AppProject를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "Policy Role": "역할", + "Policy Resource Type": "리소스 유형", + "Policy Permission": "권한", + "Policy Object": "개체", + "Policy Effect": "효과", + "No roles configured": "구성된 역할 없음", + "This AppProject does not have any roles configured.": "이 AppProject에는 구성된 역할이 없습니다.", + "Groups": "그룹", + "Policies": "정책", + "No sync windows configured": "동기화 창이 구성되지 않음", + "This AppProject does not have any sync windows configured.": "이 AppProject에는 동기화 창이 구성되어 있지 않습니다.", + "Schedule": "일정", + "Clusters": "클러스터", + "Manual Sync": "수동 동기화", + "Time Zone": "시간대", + "All": "모두", + "Allowed": "허용됨", + "Denied": "거부됨", + "Group": "그룹", + "No resources configured": "구성된 리소스 없음", + "This list does not have any resources configured.": "이 목록에는 리소스가 구성되어 있지 않습니다.", + "Traffic": "트래픽", + "Restarts": "재시작", + "Owner": "소유자", + "Memory": "메모리", "CPU": "CPU", - "Created At": "Created At", - "No pods": "No pods", - "There are no pods associated with the rollout.": "There are no pods associated with the rollout.", - "Close": "Close", - "{{x}} failed with an error.": "{{x}} failed with an error.", - "Edit Pod": "Edit Pod", - "Edit Rollout": "Edit Rollout", - "Promote": "Promote", - "Full Promote": "Full Promote", - "Abort": "Abort", - "Retry": "Retry", - "Restart": "Restart", - "Rollback": "Rollback", - "Age": "Age", - "Info": "Info", - "Ready containers": "Ready containers", - "ready": "ready", - "0 Pods": "0 Pods", - "Scaling down in:": "Scaling down in:", - "Rollout Revisions": "Rollout Revisions", - "Stable": "Stable", - "Active": "Active", - "Preview": "Preview", + "Created At": "생성 시간", + "No pods": "Pod 없음", + "There are no pods associated with the rollout.": "롤아웃과 연결된 Pod가 없습니다.", + "Close": "닫기", + "{{x}} failed with an error.": "{{x}}에서 오류가 발생하여 실패했습니다.", + "Edit Pod": "Pod 편집", + "Edit Rollout": "롤아웃 편집", + "Promote": "승격", + "Full Promote": "전체 승격", + "Abort": "중단", + "Retry": "다시 시도", + "Restart": "재시작", + "Rollback": "롤백", + "Age": "수명", + "Info": "정보", + "Ready containers": "준비된 컨테이너", + "ready": "준비 완료", + "0 Pods": "0 Pod", + "Scaling down in:": "다음 시점 이후 축소:", + "Rollout Revisions": "롤아웃 리버전", + "Stable": "안정적", + "Active": "활성", + "Preview": "미리보기", "Canary": "Canary", - "Rollout details": "Rollout details", - "Replicas": "Replicas", - "The number of desired replicas for the rollout": "The number of desired replicas for the rollout", - "The current status of the rollout": "The current status of the rollout", - "There is no rollout status. Check that the Rollout Manager is created and is available.": "There is no rollout status. Check that the Rollout Manager is created and is available.", - "Strategy": "Strategy", - "Whether the rollout is using a blue-green or canary strategy": "Whether the rollout is using a blue-green or canary strategy", - "No Argo Rollouts": "No Argo Rollouts", - "There are no Argo Rollouts in this project.": "There are no Argo Rollouts in this project.", - "There are no Argo Rollouts in all projects.": "There are no Argo Rollouts in all projects.", - "There was an error retrieving rollouts. Check your connection and reload the page.": "There was an error retrieving rollouts. Check your connection and reload the page.", - "Rollouts": "Rollouts", - "Create Rollout": "Create Rollout", - "Pods": "Pods", - "Selector": "Selector", - "Rollout Status": "Rollout Status", - "Revisions": "Revisions", - "There was an error retrieving the rollout. Check your connection and reload the page.": "There was an error retrieving the rollout. Check your connection and reload the page.", - "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "There was an error retrieving the rollout revisions. Check your connection and reload the page.", - "Active Service": "Active Service", - "The active blue-green service": "The active blue-green service", - "Preview Service": "Preview Service", - "The preview blue-green service": "The preview blue-green service", - "ClusterAnalysis Template": "ClusterAnalysis Template", - "Analysis Template": "Analysis Template", - "Stable Service": "Stable Service", - "The stable service": "The stable service", - "Canary Service": "Canary Service", - "The canary service": "The canary service", - "Analysis Templates": "Analysis Templates", - "The analysis and cluster-scoped analysis templates used for the canary strategy": "The analysis and cluster-scoped analysis templates used for the canary strategy", - "Topology view": "Topology view", - "No Argo CD Applications": "No Argo CD Applications", - "Loading Argo CD Applications...": "Loading Argo CD Applications...", - "No Argo CD Applications match the filter": "No Argo CD Applications match the filter", - "Adjust the filter to see more applications.": "Adjust the filter to see more applications.", - "There are no Argo CD Applications in this application set.": "There are no Argo CD Applications in this application set.", - "There are no Argo CD Applications in all projects.": "There are no Argo CD Applications in all projects.", - "There are no Argo CD Applications in this project.": "There are no Argo CD Applications in this project.", - "There was an error retrieving applications. Check your connection and reload the page.": "There was an error retrieving applications. Check your connection and reload the page.", - "ApplicationSet Applications": "ApplicationSet Applications", - "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.", + "Rollout details": "롤아웃 세부 정보", + "Replicas": "복제", + "The number of desired replicas for the rollout": "롤아웃에 필요한 복제본 수", + "The current status of the rollout": "롤아웃의 현재 상태", + "There is no rollout status. Check that the Rollout Manager is created and is available.": "롤아웃 상태가 없습니다. Rollout Manager가 생성되고 사용 가능한 상태인지 확인합니다.", + "Strategy": "전략", + "Whether the rollout is using a blue-green or canary strategy": "롤아웃이 Blue-Green 또는 Canary 전략을 사용하고 있는지 여부", + "No Argo Rollouts": "Argo Rollouts 없음", + "There are no Argo Rollouts in this project.": "이 프로젝트에는 Argo Rollouts이 없습니다.", + "There are no Argo Rollouts in all projects.": "모든 프로젝트에 Argo Rollouts이 없습니다.", + "There was an error retrieving rollouts. Check your connection and reload the page.": "롤아웃을 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "Rollouts": "롤아웃", + "Create Rollout": "롤아웃 생성", + "Pods": "Pod", + "Selector": "선택기", + "Rollout Status": "롤아웃 상태", + "Revisions": "개정 버전", + "There was an error retrieving the rollout. Check your connection and reload the page.": "롤아웃을 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "롤아웃 버전을 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "Active Service": "활성 서비스", + "The active blue-green service": "활성 Blue-Green 서비스", + "Preview Service": "프리뷰 서비스", + "The preview blue-green service": "Blue-Green 서비스 프리뷰", + "ClusterAnalysis Template": "ClusterAnalysis 템플릿", + "Analysis Template": "분석 템플릿", + "Stable Service": "안정적인 서비스", + "The stable service": "안정적인 서비스", + "Canary Service": "Canary 서비스", + "The canary service": "Canary 서비스", + "Analysis Templates": "분석 템플릿", + "The analysis and cluster-scoped analysis templates used for the canary strategy": "Canary 전략에 사용되는 분석 및 클러스터 범위 분석 템플릿", + "Topology view": "토폴로지 보기", + "No Argo CD Applications": "Argo CD 애플리케이션 없음", + "Loading Argo CD Applications...": "Argo CD 애플리케이션 로드 중...", + "No Argo CD Applications match the filter": "필터와 일치하는 Argo CD 애플리케이션이 없음", + "Adjust the filter to see more applications.": "필터를 조정하여 더 많은 애플리케이션을 확인합니다.", + "There are no Argo CD Applications in this application set.": "이 애플리케이션 세트에는 Argo CD 애플리케이션이 없습니다.", + "There are no Argo CD Applications in all projects.": "모든 프로젝트에 Argo CD 애플리케이션이 없습니다.", + "There are no Argo CD Applications in this project.": "이 프로젝트에 Argo CD 애플리케이션이 없습니다.", + "There was an error retrieving applications. Check your connection and reload the page.": "애플리케이션을 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", + "ApplicationSet Applications": "ApplicationSet 애플리케이션", + "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "그래프 및 테이블 보기에는 ApplicationSet의 애플리케이션이 표시됩니다. 필터를 사용하여 상태 및 동기화 상태에 따라 애플리케이션을 필터링합니다.", "Revision": "개정 버전", - "No Argo CD ApplicationSets match the filter": "No Argo CD ApplicationSets match the filter", - "Adjust the filter to see more ApplicationSets.": "Adjust the filter to see more ApplicationSets.", - "There are no Argo CD ApplicationSets in this project.": "There are no Argo CD ApplicationSets in this project.", - "There are no Argo CD ApplicationSets in all projects.": "There are no Argo CD ApplicationSets in all projects.", - "No matching Argo CD ApplicationSets": "No matching Argo CD ApplicationSets", - "No Argo CD ApplicationSets": "No Argo CD ApplicationSets", - "There was an error retrieving applicationsets. Check your connection and reload the page.": "There was an error retrieving applicationsets. Check your connection and reload the page.", + "No Argo CD ApplicationSets match the filter": "필터와 일치하는 Argo CD ApplicationSet이 없음", + "Adjust the filter to see more ApplicationSets.": "더 많은 ApplicationSet을 확인하려면 필터를 조정합니다.", + "There are no Argo CD ApplicationSets in this project.": "이 프로젝트에 Argo CD ApplicationSets가 없습니다.", + "There are no Argo CD ApplicationSets in all projects.": "모든 프로젝트에 Argo CD ApplicationSets가 없습니다.", + "No matching Argo CD ApplicationSets": "일치하는 Argo CD ApplicationSets 없음", + "No Argo CD ApplicationSets": "Argo CD ApplicationSets 없음", + "There was an error retrieving applicationsets. Check your connection and reload the page.": "applicationsets를 검색하는 동안 오류가 발생했습니다. 연결을 확인하고 페이지를 다시 로드합니다.", "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "Create ApplicationSet", - "No labels": "No labels", - "Namespace defines the space within which each name must be unique.": "Namespace defines the space within which each name must be unique.", - "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Map of string keys and values that can be used to organize and categorize (scope and select) objects.", - "Edit": "Edit", - "Annotations": "Annotations", - "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.", - "Created at": "Created at", - "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", - "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "List view": "List view", - "Graph view": "Graph view", - "Sync": "Sync", - "Stop": "Stop", - "Refresh": "Refresh", - "Refresh (Hard)": "Refresh (Hard)", - "Actions": "Actions", - "You don't have permission to perform this action": "You don't have permission to perform this action", - "annotations": "annotations", - "annotation": "annotation", - "No owner": "No owner", + "Create ApplicationSet": "ApplicationSet 만들기", + "No labels": "레이블 없음", + "Namespace defines the space within which each name must be unique.": "네임 스페이스는 각 이름을 고유해야 하는 공간을 정의합니다.", + "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "객체를 구성하고 분류(범위 지정 및 선택)하는 데 사용할 수 있는 문자열 키와 값의 맵입니다.", + "Edit": "편집", + "Annotations": "주석", + "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "주석은 리소스와 함께 저장되는 비구조화된 키-값 맵으로, 외부 도구가 임의의 메타데이터를 저장하고 검색하는 데 사용할 수 있습니다. 이는 쿼리할 수 없으며 오브젝트를 수정할 때 보존되어야 합니다.", + "Created at": "생성 시간", + "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time은 시간을 나타내는 래퍼입니다. Time 타입은 올바른 YAML 및 JSON 마샬링을 지원합니다.", + "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "소유자 참조는 이 리소스를 상위 객체에 연결합니다. 예를 들어 ApplicationSet에서 생성된 애플리케이션은 해당 ApplicationSet이 소유자로 지정됩니다. 이 관계를 통해 적절한 리소스 라이프사이클 관리 및 가비지 컬렉션이 가능합니다.", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", @@ -360,5 +349,16 @@ "Go to last page": "Go to last page", "Items per page": "Items per page", "per page": "per page", - "of": "of" + "of": "of", + "List view": "목록 보기", + "Graph view": "그래프 보기", + "Sync": "동기화", + "Stop": "중지", + "Refresh": "새로 고침", + "Refresh (Hard)": "새로 고침(강제)", + "Actions": "작업", + "You don't have permission to perform this action": "이 작업을 수행할 수 있는 권한이 없습니다", + "annotations": "주석", + "annotation": "주석", + "No owner": "소유자 없음" } diff --git a/locales/ko/plugin__gitops-public.json b/locales/ko/plugin__gitops-public.json index f0284a431..2f97051d6 100644 --- a/locales/ko/plugin__gitops-public.json +++ b/locales/ko/plugin__gitops-public.json @@ -1,28 +1,28 @@ { - "Error": "Error", - "Receiving Traffic": "Receiving Traffic", - "Not Receiving Traffic": "Not Receiving Traffic", - "View logs": "View logs", - "Open URL": "Open URL", - "Edit": "Edit", - "Rollout": "Rollout", - "Name": "Name", - "Namespace": "Namespace", - "Annotations": "Annotations", - "No annotations": "No annotations", - "Labels": "Labels", - "No labels": "No labels", - "Update Strategy": "Update Strategy", - "Replicas": "Replicas", - "Revision History Limit": "Revision History Limit", + "Error": "오류", + "Receiving Traffic": "트래픽 수신", + "Not Receiving Traffic": "트래픽을 수신하지 않음", + "View logs": "로그보기", + "Open URL": "URL 열기", + "Edit": "편집", + "Rollout": "롤아웃", + "Name": "이름", + "Namespace": "네임 스페이스", + "Annotations": "주석", + "No annotations": "주석 없음", + "Labels": "라벨", + "No labels": "라벨 없음", + "Update Strategy": "업데이트 전략", + "Replicas": "복제", + "Revision History Limit": "개정 이력 제한", "True": "True", "False": "False", - "Type": "Type", - "Status": "Status", - "Updated": "Updated", - "Reason": "Reason", - "Message": "Message", - "No conditions found": "No conditions found", - "No owner": "No owner", - "View {{kind}}": "View {{kind}}" + "Type": "유형", + "Status": "상태", + "Updated": "업데이트됨", + "Reason": "이유", + "Message": "메시지", + "No conditions found": "조건을 찾을 수 없습니다.", + "No owner": "소유자 없음", + "View {{kind}}": "{{kind}} 보기" } diff --git a/locales/zh/plugin__gitops-console-app.json b/locales/zh/plugin__gitops-console-app.json index 678eb48b7..da4481d97 100644 --- a/locales/zh/plugin__gitops-console-app.json +++ b/locales/zh/plugin__gitops-console-app.json @@ -1,11 +1,11 @@ { - "Name is required.": "Name is required.", - "Name can only contain letters, numbers, spaces, and hyphens.": "Name can only contain letters, numbers, spaces, and hyphens.", - "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.", - "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.", - "Remove from favorites": "Remove from favorites", - "Add to favorites": "Add to favorites", - "Save": "Save", - "Cancel": "Cancel", - "Name": "Name" + "Name is required.": "名称是必需的。", + "Name can only contain letters, numbers, spaces, and hyphens.": "名称只能包含字母、数字、空格和连字符。", + "The name {{favoriteName}} already exists in your favorites. Choose a unique name to save to your favorites.": "名称 {{favoriteName}} 已存在于您的收藏中。选择一个唯一的名称保存到您的收藏中。", + "Maximum number of favorites ({{maxCount}}) reached. To add another favorite, remove an existing page from your favorites.": "已达到最大收藏数 ({{maxCount}})。要添加另一个收藏,请从您的收藏中删除一个已有的。", + "Remove from favorites": "从喜爱中删除", + "Add to favorites": "添加到喜爱", + "Save": "保存", + "Cancel": "取消", + "Name": "名称" } diff --git a/locales/zh/plugin__gitops-olm.json b/locales/zh/plugin__gitops-olm.json index 2345b476e..18b3c0ca0 100644 --- a/locales/zh/plugin__gitops-olm.json +++ b/locales/zh/plugin__gitops-olm.json @@ -1,5 +1,5 @@ { - "Show operands in:": "Show operands in:", - "All namespaces": "All namespaces", - "Current namespace only": "Current namespace only" + "Show operands in:": "显示以下的操作项:", + "All namespaces": "所有命名空间", + "Current namespace only": "仅限当前命名空间" } diff --git a/locales/zh/plugin__gitops-plugin.json b/locales/zh/plugin__gitops-plugin.json index f01dea6bc..3db9df646 100644 --- a/locales/zh/plugin__gitops-plugin.json +++ b/locales/zh/plugin__gitops-plugin.json @@ -1,358 +1,347 @@ { - "Application details": "Application details", - "Health Status": "Health Status", - "Health status represents the overall health of the application.": "Health status represents the overall health of the application.", - "Current Sync Status": "Current Sync Status", - "Sync status represents the current synchronized state for the application.": "Sync status represents the current synchronized state for the application.", - "Last Sync Status": "Last Sync Status", - "The result of the last sync status.": "The result of the last sync status.", - "Target Revision": "Target Revision", - "The specified revision for the Application.": "The specified revision for the Application.", - "Project": "Project", - "The Argo CD Project that this application belongs to.": "The Argo CD Project that this application belongs to.", - "Destination": "Destination", - "The cluster and namespace where the application is targeted": "The cluster and namespace where the application is targeted", - "Sync Policy": "Sync Policy", - "Provides options to determine application synchronization behavior": "Provides options to determine application synchronization behavior", + "Application details": "应用程序详情", + "Health Status": "健康状态", + "Health status represents the overall health of the application.": "健康状态代表应用程序的整体健康状况。", + "Current Sync Status": "当前同步状态", + "Sync status represents the current synchronized state for the application.": "同步状态代表应用程序的当前同步状态。", + "Last Sync Status": "最后同步状态", + "The result of the last sync status.": "最后同步状态的结果。", + "Target Revision": "目标版本", + "The specified revision for the Application.": "应用程序的指定版本。", + "Project": "项目", + "The Argo CD Project that this application belongs to.": "此应用程序所属的 Argo CD 项目。", + "Destination": "目的地", + "The cluster and namespace where the application is targeted": "应用所指向的集群和命名空间", + "Sync Policy": "同步策略", + "Provides options to determine application synchronization behavior": "提供用于确定应用同步行为的选项", "Automated": "Automated", "Prune": "Prune", "Self Heal": "Self Heal", - "Sync history": "Sync history", - "Details": "Details", + "Sync history": "同步历史记录", + "Details": "详情", "YAML": "YAML", - "Sources": "Sources", + "Sources": "源", "Resources": "资源", - "Sync Status": "Sync Status", - "History": "History", - "Events": "Events", - "Application resources": "Application resources", - "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.", - "No resources": "No resources", - "There are no resources associated with the application.": "There are no resources associated with the application.", - "There are no resources based on the applied filters. Adjust the filters to see more resources.": "There are no resources based on the applied filters. Adjust the filters to see more resources.", - "Search by name...": "Search by name...", - "Name": "Name", - "Namespace": "Namespace", - "Sync Wave": "Sync Wave", - "No Sync Status": "No Sync Status", - "None": "None", - "Kind": "Kind", - "Type": "Type", - "Repository": "Repository", - "Path / Chart": "Path / Chart", - "Ref": "Ref", - "No source": "No source", - "Error. There must at least one source in the application.": "Error. There must at least one source in the application.", - "Application sources": "Application sources", - "Sync status": "Sync status", - "Operation": "Operation", - "The operation that was performed.": "The operation that was performed.", - "Phase": "Phase", - "The operation phase.": "The operation phase.", + "Sync Status": "同步状态", + "History": "历史记录", + "Events": "事件", + "Application resources": "应用程序资源", + "The graph and table views show health and sync status for the application's immediate resources only. Click the Argo CD Link to see the complete resource tree. Use the filter to filter resources based on status and kind.": "图形和表视图仅显示应用程序的直接资源的健康状态和同步状态。点击 Argo CD Link 查看完整的资源树。使用筛选条件按状态和类型筛选资源。", + "No resources": "没有资源", + "There are no resources associated with the application.": "没有与应用程序关联的资源。", + "There are no resources based on the applied filters. Adjust the filters to see more resources.": "没有符合当前筛选条件的资源。调整过滤器以查看更多资源。", + "Search by name...": "按名称搜索...", + "Name": "名称", + "Namespace": "命名空间", + "Sync Wave": "同步 Wave", + "No Sync Status": "没有同步状态", + "None": "无", + "Kind": "种类(Kind)", + "Type": "类型", + "Repository": "软件仓库", + "Path / Chart": "路径/图表", + "Ref": "引用", + "No source": "无源", + "Error. There must at least one source in the application.": "错误应用程序中必须至少有一个源。", + "Application sources": "应用程序源", + "Sync status": "同步状态", + "Operation": "操作", + "The operation that was performed.": "执行的操作。", + "Phase": "阶段", + "The operation phase.": "操作阶段。", "Message": "消息", - "The message from the operation.": "The message from the operation.", - "Initiated By": "Initiated By", - "Who initiated the operation.": "Who initiated the operation.", - "automated sync policy": "automated sync policy", - "Started At": "Started At", - "When the operation was started.": "When the operation was started.", - "Duration": "Duration", - "How long the operation took to complete.": "How long the operation took to complete.", - "Finished At": "Finished At", - "When the operation was finished.": "When the operation was finished.", - "Resources Last Synced": "Resources Last Synced", - "Status": "Status", + "The message from the operation.": "操作的消息。", + "Initiated By": "启动者", + "Who initiated the operation.": "谁启动了操作。", + "automated sync policy": "自动同步策略", + "Started At": "开始于", + "When the operation was started.": "启动该操作的时间。", + "Duration": "持续时间", + "How long the operation took to complete.": "操作完成所需的时间。", + "Finished At": "完成时间", + "When the operation was finished.": "操作完成后。", + "Resources Last Synced": "最后同步的资源", + "Status": "状态", "Hook": "Hook", - "Edit labels": "Edit labels", - "Edit annotations": "Edit annotations", - "Delete {{x}}": "Delete {{x}}", - "Edit {{x}}": "Edit {{x}}", - "View in Argo CD": "View in Argo CD", - "View Details": "View Details", - "Edit Application": "Edit Application", - "Delete Application": "Delete Application", - "Show {{x}}": "Show {{x}}", - "Hide {{x}}": "Hide {{x}}", - "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}", - "Group resources of the same kind into one node": "Group resources of the same kind into one node", - "Group Nodes": "Group Nodes", - "There is no health status for this resource": "There is no health status for this resource", + "Edit labels": "编辑标签", + "Edit annotations": "编辑注解", + "Delete {{x}}": "删除 {{x}}", + "Edit {{x}}": "编辑 {{x}}", + "View in Argo CD": "在 Argo CD 里查看 ", + "View Details": "查看详情", + "Edit Application": "编辑应用程序", + "Delete Application": "删除应用程序", + "Show {{x}}": "显示 {{x}}", + "Hide {{x}}": "隐藏 {{x}}", + "Toggle between OpenShift shapes and Argo CD shapes for tree nodes. Current setting: {{x}}": "切换树节点的 OpenShift/Argo CD 图形样式。当前设置:{{x}}", + "Group resources of the same kind into one node": "将相同种类的资源分组到一个节点中", + "Group Nodes": "组节点", + "There is no health status for this resource": "此资源暂无健康状态", "Unknown": "未知", - "Sync Unknown": "Sync Unknown", - "One or more resources are in Progressing state": "One or more resources are in Progressing state", - "Step {{x}}": "Step {{x}}", - "Step: unmatched": "Step: unmatched", + "Sync Unknown": "同步状态未知", + "One or more resources are in Progressing state": "一个或多个资源处于 Progressing 状态", + "Step {{x}}": "第 {{x}} 步", + "Step: unmatched": "步骤:不匹配", "No history": "没有历史记录", - "There is no history associated with the application.": "There is no history associated with the application.", + "There is no history associated with the application.": "没有与应用程序关联的历史记录。", "ID": "ID", - "Deploy Started At": "Deploy Started At", - "Deployed At": "Deployed At", - "Revision(s) and Source Repo URL(s)": "Revision(s) and Source Repo URL(s)", - "ApplicationSet details": "ApplicationSet details", - "Current health status of the ApplicationSet.": "Current health status of the ApplicationSet.", - "Generated Apps": "Generated Apps", - "Number of applications generated by this ApplicationSet.": "Number of applications generated by this ApplicationSet.", - "application": "application", - "applications": "applications", - "Generators": "Generators", - "Number of generators configured in this ApplicationSet.": "Number of generators configured in this ApplicationSet.", - "generator": "generator", - "generators": "generators", - "App Project": "App Project", - "Argo CD project that this ApplicationSet belongs to.": "Argo CD project that this ApplicationSet belongs to.", - "Git repository URL where the ApplicationSet configuration is stored.": "Git repository URL where the ApplicationSet configuration is stored.", - "Progressive Sync Step {{x}}": "Progressive Sync Step {{x}}", - "Applications": "Applications", - "Show all match expressions": "Show all match expressions", - "Edit ApplicationSet": "Edit ApplicationSet", - "Delete ApplicationSet": "Delete ApplicationSet", - "View Graph": "View Graph", - "Match Expressions": "Match Expressions", - "Name must be unique within a namespace.": "Name must be unique within a namespace.", - "AppSet ownerReference Tree View": "AppSet ownerReference Tree View", - "Progressive Sync Flow View": "Progressive Sync Flow View", - "Expand or collapse all progressive sync step groups": "Expand or collapse all progressive sync step groups", - "No Applications In This Step": "No Applications In This Step", - "Edit ImageUpdater": "Edit ImageUpdater", - "Delete ImageUpdater": "Delete ImageUpdater", - "Error: Missing required route parameters": "Error: Missing required route parameters", - "True": "True", - "False": "False", - "ImageUpdater details": "ImageUpdater details", - "Ready": "Ready", - "Whether the last reconciliation completed without errors.": "Whether the last reconciliation completed without errors.", - "Applications Matched": "Applications Matched", - "Number of applications matched by this ImageUpdater.": "Number of applications matched by this ImageUpdater.", - "Images Managed": "Images Managed", - "Number of images eligible for update checking.": "Number of images eligible for update checking.", - "Last Checked At": "Last Checked At", - "When the controller last checked for image updates.": "When the controller last checked for image updates.", - "Last Updated At": "Last Updated At", - "When the controller last performed an image update.": "When the controller last performed an image update.", - "Observed Generation": "Observed Generation", - "The generation of the resource that was last reconciled.": "The generation of the resource that was last reconciled.", - "Conditions": "Conditions", - "No ImageUpdaters match the search filter": "No ImageUpdaters match the search filter", - "Try removing the filter or searching for a different term to see more ImageUpdaters.": "Try removing the filter or searching for a different term to see more ImageUpdaters.", - "There are no ImageUpdaters in this namespace.": "There are no ImageUpdaters in this namespace.", - "There are no ImageUpdaters in all namespaces.": "There are no ImageUpdaters in all namespaces.", - "No matching ImageUpdaters": "No matching ImageUpdaters", - "No ImageUpdaters": "No ImageUpdaters", - "Unable to load data": "Unable to load data", - "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "There was an error retrieving ImageUpdaters. Check your connection and reload the page.", + "Deploy Started At": "部署开始时间", + "Deployed At": "部署时间", + "Revision(s) and Source Repo URL(s)": "版本及源代码仓库地址", + "ApplicationSet details": "ApplicationSet 详情", + "Current health status of the ApplicationSet.": "ApplicationSet 的当前健康状况。", + "Generated Apps": "生成的应用程序", + "Number of applications generated by this ApplicationSet.": "此 ApplicationSet 生成的应用程序数量。", + "application": "应用程序", + "applications": "应用程序", + "Generators": "生成器", + "Number of generators configured in this ApplicationSet.": "这个 ApplicationSet 中配置的生成器数量。", + "generator": "生成器", + "generators": "生成器", + "App Project": "AppProject", + "Argo CD project that this ApplicationSet belongs to.": "此 ApplicationSet 所属的 Argo CD 项目。", + "Git repository URL where the ApplicationSet configuration is stored.": "存储 ApplicationSet 配置的 Git 存储库 URL。", + "Progressive Sync Step {{x}}": "渐进式同步步骤 {{x}}", + "Applications": "应用程序", + "Show all match expressions": "显示所有匹配表达式", + "Edit ApplicationSet": "编辑 ApplicationSet", + "Delete ApplicationSet": "删除 ApplicationSet", + "View Graph": "查看图", + "Match Expressions": "匹配表达式", + "Name must be unique within a namespace.": "在命名空间中资源名称必须是唯一的。", + "AppSet ownerReference Tree View": "AppSet ownerReference 树视图", + "Progressive Sync Flow View": "渐进式同步流程视图", + "Expand or collapse all progressive sync step groups": "展开或折叠所有渐进式同步步骤组", + "No Applications In This Step": "此步骤中没有应用程序", + "Edit ImageUpdater": "编辑 ImageUpdater", + "Delete ImageUpdater": "删除 ImageUpdater", + "Error: Missing required route parameters": "错误:缺少必需的路由参数", + "True": "真", + "False": "假", + "ImageUpdater details": "ImageUpdater 详情", + "Ready": "就绪", + "Whether the last reconciliation completed without errors.": "上次协调是否顺利完成且未发生错误。", + "Applications Matched": "匹配的应用程序", + "Number of applications matched by this ImageUpdater.": "此 ImageUpdater 匹配的应用程序数量。", + "Images Managed": "管理的镜像", + "Number of images eligible for update checking.": "符合更新检查资格的镜像数量。", + "Last Checked At": "上次检查时间", + "When the controller last checked for image updates.": "控制器上次检查镜像更新的时间。", + "Last Updated At": "上次更新时间", + "When the controller last performed an image update.": "控制器上次执行镜像更新的时间。", + "Observed Generation": "已观测的版本号", + "The generation of the resource that was last reconciled.": "上次协调的资源版本号。", + "Conditions": "条件", + "No ImageUpdaters match the search filter": "没有与搜索过滤器匹配的 ImageUpdaters", + "Try removing the filter or searching for a different term to see more ImageUpdaters.": "移除筛选条件或搜索其他关键词,以查看更多 ImageUpdaters。", + "There are no ImageUpdaters in this namespace.": "这个命名空间中没有 ImageUpdaters。", + "There are no ImageUpdaters in all namespaces.": "所有命名空间中都没有 ImageUpdaters。", + "No matching ImageUpdaters": "没有匹配的 ImageUpdaters", + "No ImageUpdaters": "没有 ImageUpdaters", + "Unable to load data": "无法加载数据", + "There was an error retrieving ImageUpdaters. Check your connection and reload the page.": "获取 ImageUpdater 时出错。检查您的连接并重新载入页面。", "ImageUpdaters": "ImageUpdaters", - "Create ImageUpdater": "Create ImageUpdater", - "Apps": "Apps", - "Images": "Images", - "Last Checked": "Last Checked", - "Labels": "Labels", - "Has Apps": "Has Apps", - "No Apps": "No Apps", - "Not Ready": "Not Ready", - "Recent Updates": "Recent Updates", + "Create ImageUpdater": "创建 ImageUpdater", + "Apps": "应用", + "Images": "镜像", + "Last Checked": "上次检查时间", + "Labels": "标签", + "Has Apps": "有应用程序", + "No Apps": "没有应用程序", + "Not Ready": "未就绪", + "Recent Updates": "最新的更新", "ArgoCD ImageUpdater": "ArgoCD ImageUpdater", - "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "There was an error retrieving the ImageUpdater. Check your connection and reload the page.", - "No recent updates": "No recent updates", - "No image updates have been recorded in the most recent reconciliation cycle.": "No image updates have been recorded in the most recent reconciliation cycle.", - "Alias": "Alias", - "Image": "Image", - "New Version": "New Version", - "Apps Updated": "Apps Updated", - "Updated At": "Updated At", - "Server": "Server", - "Deny": "Deny", - "Allow": "Allow", - "No destinations configured": "No destinations configured", - "This AppProject does not have any destinations configured.": "This AppProject does not have any destinations configured.", - "Edit AppProject": "Edit AppProject", - "Delete": "Delete", - "Allowed Sources": "Allowed Sources", - "Allowed Sources help": "Git repositories and namespaces that are allowed as sources for applications in this project.", - "Repositories": "Repositories", - "Namespaces": "Namespaces", - "Allowed Destinations": "Allowed Destinations", - "Allowed Destinations help": "Clusters and namespaces where applications in this project are allowed to be deployed.", - "Resource Allow/Deny Lists": "Resource Allow/Deny Lists", - "Resource Allow/Deny Lists help": "Lists of Kubernetes resources that are allowed or denied for applications in this project. Cluster-scoped resources apply to all clusters, while namespace-scoped resources apply to specific namespaces.", - "Cluster Resource Allow List": "Cluster Resource Allow List", - "Cluster Resource Deny List": "Cluster Resource Deny List", - "Namespace Resource Allow List": "Namespace Resource Allow List", - "Namespace Resource Deny List": "Namespace Resource Deny List", - "AppProject details": "AppProject details", - "Project Type": "Project Type", - "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.", - "Default Project": "Default Project", - "Description": "Description", - "Description of the AppProject.": "Description of the AppProject.", - "Number of applications using this AppProject.": "Number of applications using this AppProject.", - "Destinations": "Destinations", - "Number of clusters and namespaces where applications are allowed to be deployed.": "Number of clusters and namespaces where applications are allowed to be deployed.", - "destination": "destination", - "destinations": "destinations", - "Source Repositories": "Source Repositories", - "Number of allowed source repositories for this AppProject.": "Number of allowed source repositories for this AppProject.", - "repository": "repository", - "repositories": "repositories", - "Source Namespaces": "Source Namespaces", - "Number of allowed source namespaces for this AppProject.": "Number of allowed source namespaces for this AppProject.", - "namespace": "namespace", - "namespaces": "namespaces", - "Roles": "Roles", - "Number of roles configured in this AppProject.": "Number of roles configured in this AppProject.", - "role": "role", - "roles": "roles", - "Sync Windows": "Sync Windows", - "Number of sync windows configured in this AppProject.": "Number of sync windows configured in this AppProject.", - "sync window": "sync window", - "sync windows": "sync windows", - "Project-Scoped Clusters Only": "Project-Scoped Clusters Only", - "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.", - "Enabled": "Enabled", - "Disabled": "Disabled", - "No Argo CD App Projects match the search filter": "No Argo CD App Projects match the search filter", - "Try removing the filter or searching for a different term to see more App Projects.": "Try removing the filter or searching for a different term to see more App Projects.", - "There are no Argo CD App Projects in this project.": "There are no Argo CD App Projects in this project.", - "There are no Argo CD App Projects in all projects.": "There are no Argo CD App Projects in all projects.", - "No matching Argo CD App Projects": "No matching Argo CD App Projects", - "No Argo CD App Projects": "No Argo CD App Projects", - "There was an error retrieving App Projects. Check your connection and reload the page.": "There was an error retrieving App Projects. Check your connection and reload the page.", + "There was an error retrieving the ImageUpdater. Check your connection and reload the page.": "获取 ImageUpdater 时出错。检查您的连接并重新载入页面。", + "No recent updates": "暂无近期更新", + "No image updates have been recorded in the most recent reconciliation cycle.": "最新协调周期中没有记录镜像更新。", + "Alias": "别名", + "Image": "镜像", + "New Version": "新版本", + "Apps Updated": "已更新的应用程序", + "Updated At": "更新时间", + "Server": "服务器", + "Deny": "拒绝", + "Allow": "允许", + "No destinations configured": "没有配置目的地", + "This AppProject does not have any destinations configured.": "这个 AppProject 没有配置任何目的地。", + "Edit AppProject": "编辑 AppProject", + "Delete": "删除", + "Allowed Sources": "允许的源", + "Allowed Sources help": "允许作为此项目中应用程序源的 Git 存储库和命名空间。", + "Repositories": "存储库", + "Namespaces": "命名空间", + "Allowed Destinations": "允许的目标", + "Allowed Destinations help": "此项目中的应用允许部署到的集群和命名空间。", + "Resource Allow/Deny Lists": "资源允许/拒绝列表", + "Resource Allow/Deny Lists help": "此项目中应用程序允许或拒绝的 Kubernetes 资源列表。集群范围资源适用于所有集群,而命名空间范围资源适用于特定命名空间。", + "Cluster Resource Allow List": "集群资源允许列表", + "Cluster Resource Deny List": "集群资源拒绝列表", + "Namespace Resource Allow List": "命名空间资源允许列表", + "Namespace Resource Deny List": "命名空间资源拒绝列表", + "AppProject details": "AppProject 详情", + "Project Type": "项目类型", + "The default project is created automatically and cannot be deleted. It can be modified but is recommended to create dedicated projects for production use.": "default 项目是自动创建的,无法删除。它可以进行修改,但建议为生产环境创建专用的项目。", + "Default Project": "默认项目", + "Description": "描述", + "Description of the AppProject.": "AppProject 的描述。", + "Number of applications using this AppProject.": "使用这个 AppProject 的应用数量。", + "Destinations": "目标", + "Number of clusters and namespaces where applications are allowed to be deployed.": "允许应用部署到的集群和命名空间数量。", + "destination": "目的地", + "destinations": "目的地", + "Source Repositories": "源存储库", + "Number of allowed source repositories for this AppProject.": "此 AppProject 允许的源存储库的数量。", + "repository": "软件仓库", + "repositories": "存储库", + "Source Namespaces": "源命名空间", + "Number of allowed source namespaces for this AppProject.": "此 AppProject 允许的源命名空间数量。", + "namespace": "命名空间", + "namespaces": "命名空间", + "Roles": "角色", + "Number of roles configured in this AppProject.": "此 AppProject 中配置的角色数量。", + "role": "角色", + "roles": "角色", + "Sync Windows": "同步窗口", + "Number of sync windows configured in this AppProject.": "此 AppProject 中配置同步窗口的数量。", + "sync window": "同步窗口", + "sync windows": "同步窗口", + "Project-Scoped Clusters Only": "仅项目范围内的集群", + "When enabled, applications can only be deployed to clusters that are scoped to this project. This prevents deploying to clusters that are not part of the project.": "启用后,应用程序只能部署到此项目范围内的集群。这可以防止部署到不属于此项目的集群。", + "Enabled": "已启用", + "Disabled": "禁用", + "No Argo CD App Projects match the search filter": "没有符合搜索筛选条件的 Argo CD 项目", + "Try removing the filter or searching for a different term to see more App Projects.": "尝试移除筛选条件或搜索其他词,以查看更多 App 项目。", + "There are no Argo CD App Projects in this project.": "此项目中没有 Argo CD App 项目。", + "There are no Argo CD App Projects in all projects.": "所有项目中都没有 Argo CD App 项目。", + "No matching Argo CD App Projects": "不匹配 Argo CD 应用程序项目", + "No Argo CD App Projects": "没有 Argo CD 应用程序项目", + "There was an error retrieving App Projects. Check your connection and reload the page.": "获取 App 项目时出错。检查您的连接并重新载入页面。", "AppProjects": "AppProjects", - "Create AppProject": "Create AppProject", - "Last Updated": "Last Updated", - "Has Description": "Has Description", - "No Description": "No Description", - "Has Applications": "Has Applications", - "No Applications": "No Applications", - "Custom Projects": "Custom Projects", - "Has Source Repos": "Has Source Repos", - "No Source Repos": "No Source Repos", - "Has Destinations": "Has Destinations", - "No Destinations": "No Destinations", - "Allow/Deny": "Allow/Deny", + "Create AppProject": "创建 AppProject", + "Last Updated": "最后更新", + "Has Description": "具有描述", + "No Description": "没有描述", + "Has Applications": "具有应用程序", + "No Applications": "没有应用程序", + "Custom Projects": "自定义项目", + "Has Source Repos": "具有源存储库", + "No Source Repos": "没有源存储库", + "Has Destinations": "有目标", + "No Destinations": "无目标", + "Allow/Deny": "允许/拒绝", "ArgoCD AppProject": "ArgoCD AppProject", - "There was an error retrieving the AppProject. Check your connection and reload the page.": "There was an error retrieving the AppProject. Check your connection and reload the page.", - "Policy Role": "Policy Role", - "Policy Resource Type": "Policy Resource Type", - "Policy Permission": "Policy Permission", - "Policy Object": "Policy Object", - "Policy Effect": "Policy Effect", - "No roles configured": "No roles configured", - "This AppProject does not have any roles configured.": "This AppProject does not have any roles configured.", - "Groups": "Groups", - "Policies": "Policies", - "No sync windows configured": "No sync windows configured", - "This AppProject does not have any sync windows configured.": "This AppProject does not have any sync windows configured.", - "Schedule": "Schedule", - "Clusters": "Clusters", - "Manual Sync": "Manual Sync", - "Time Zone": "Time Zone", - "All": "All", - "Allowed": "Allowed", - "Denied": "Denied", - "Group": "Group", - "No resources configured": "No resources configured", - "This list does not have any resources configured.": "This list does not have any resources configured.", - "Traffic": "Traffic", - "Restarts": "Restarts", - "Owner": "Owner", - "Memory": "Memory", + "There was an error retrieving the AppProject. Check your connection and reload the page.": "获取 AppProject 时出错。检查您的连接并重新载入页面。", + "Policy Role": "角色", + "Policy Resource Type": "资源类型", + "Policy Permission": "权限", + "Policy Object": "对象", + "Policy Effect": "影响", + "No roles configured": "没有配置角色", + "This AppProject does not have any roles configured.": "此 AppProject 没有配置任何角色。", + "Groups": "组", + "Policies": "策略", + "No sync windows configured": "没有配置同步窗口", + "This AppProject does not have any sync windows configured.": "这个 AppProject 没有配置任何同步窗口。", + "Schedule": "调度", + "Clusters": "集群", + "Manual Sync": "手动同步", + "Time Zone": "时区", + "All": "所有", + "Allowed": "已允许", + "Denied": "已拒绝", + "Group": "组", + "No resources configured": "没有配置资源", + "This list does not have any resources configured.": "此列表没有配置任何资源。", + "Traffic": "网络流量", + "Restarts": "重启", + "Owner": "所有者", + "Memory": "内存", "CPU": "CPU", - "Created At": "Created At", - "No pods": "No pods", - "There are no pods associated with the rollout.": "There are no pods associated with the rollout.", - "Close": "Close", - "{{x}} failed with an error.": "{{x}} failed with an error.", - "Edit Pod": "Edit Pod", - "Edit Rollout": "Edit Rollout", - "Promote": "Promote", - "Full Promote": "Full Promote", - "Abort": "Abort", - "Retry": "Retry", - "Restart": "Restart", - "Rollback": "Rollback", - "Age": "Age", - "Info": "Info", - "Ready containers": "Ready containers", - "ready": "ready", - "0 Pods": "0 Pods", - "Scaling down in:": "Scaling down in:", - "Rollout Revisions": "Rollout Revisions", - "Stable": "Stable", - "Active": "Active", - "Preview": "Preview", + "Created At": "创建时间", + "No pods": "没有 pod", + "There are no pods associated with the rollout.": "没有与 Rollout 关联的 pod。", + "Close": "关闭", + "{{x}} failed with an error.": "{{x}} 失败并显示错误。", + "Edit Pod": "编辑 Pod", + "Edit Rollout": "编辑 Rollout", + "Promote": "推进", + "Full Promote": "完全推进", + "Abort": "终止", + "Retry": "重试", + "Restart": "重启", + "Rollback": "回滚", + "Age": "年龄", + "Info": "信息", + "Ready containers": "就绪容器", + "ready": "就绪", + "0 Pods": "0 个 Pod", + "Scaling down in:": "将在以下时间后缩容:", + "Rollout Revisions": "Rollout 修订版本", + "Stable": "稳定", + "Active": "活跃", + "Preview": "预览", "Canary": "Canary", - "Rollout details": "Rollout details", - "Replicas": "Replicas", - "The number of desired replicas for the rollout": "The number of desired replicas for the rollout", - "The current status of the rollout": "The current status of the rollout", - "There is no rollout status. Check that the Rollout Manager is created and is available.": "There is no rollout status. Check that the Rollout Manager is created and is available.", - "Strategy": "Strategy", - "Whether the rollout is using a blue-green or canary strategy": "Whether the rollout is using a blue-green or canary strategy", - "No Argo Rollouts": "No Argo Rollouts", - "There are no Argo Rollouts in this project.": "There are no Argo Rollouts in this project.", - "There are no Argo Rollouts in all projects.": "There are no Argo Rollouts in all projects.", - "There was an error retrieving rollouts. Check your connection and reload the page.": "There was an error retrieving rollouts. Check your connection and reload the page.", + "Rollout details": "Rollout 详情", + "Replicas": "副本", + "The number of desired replicas for the rollout": "Rollout 所需的副本数", + "The current status of the rollout": "Rollout 的当前状态", + "There is no rollout status. Check that the Rollout Manager is created and is available.": "没有 rollout 状态。检查 Rollout Manager 是否已创建并可用。", + "Strategy": "策略", + "Whether the rollout is using a blue-green or canary strategy": "Rollout 是否使用 Blue-Green 还是 Canary 策略", + "No Argo Rollouts": "没有 Argo Rollouts", + "There are no Argo Rollouts in this project.": "此项目中没有 Argo Rollouts。", + "There are no Argo Rollouts in all projects.": "所有项目中都没有 Argo Rollouts。", + "There was an error retrieving rollouts. Check your connection and reload the page.": "获取 Rollout 时出错。检查您的连接并重新载入页面。", "Rollouts": "Rollouts", - "Create Rollout": "Create Rollout", - "Pods": "Pods", - "Selector": "Selector", - "Rollout Status": "Rollout Status", - "Revisions": "Revisions", - "There was an error retrieving the rollout. Check your connection and reload the page.": "There was an error retrieving the rollout. Check your connection and reload the page.", - "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "There was an error retrieving the rollout revisions. Check your connection and reload the page.", - "Active Service": "Active Service", - "The active blue-green service": "The active blue-green service", - "Preview Service": "Preview Service", - "The preview blue-green service": "The preview blue-green service", - "ClusterAnalysis Template": "ClusterAnalysis Template", - "Analysis Template": "Analysis Template", - "Stable Service": "Stable Service", - "The stable service": "The stable service", - "Canary Service": "Canary Service", - "The canary service": "The canary service", - "Analysis Templates": "Analysis Templates", - "The analysis and cluster-scoped analysis templates used for the canary strategy": "The analysis and cluster-scoped analysis templates used for the canary strategy", - "Topology view": "Topology view", - "No Argo CD Applications": "No Argo CD Applications", - "Loading Argo CD Applications...": "Loading Argo CD Applications...", - "No Argo CD Applications match the filter": "No Argo CD Applications match the filter", - "Adjust the filter to see more applications.": "Adjust the filter to see more applications.", - "There are no Argo CD Applications in this application set.": "There are no Argo CD Applications in this application set.", - "There are no Argo CD Applications in all projects.": "There are no Argo CD Applications in all projects.", - "There are no Argo CD Applications in this project.": "There are no Argo CD Applications in this project.", - "There was an error retrieving applications. Check your connection and reload the page.": "There was an error retrieving applications. Check your connection and reload the page.", - "ApplicationSet Applications": "ApplicationSet Applications", - "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.", - "Revision": "修订", - "No Argo CD ApplicationSets match the filter": "No Argo CD ApplicationSets match the filter", - "Adjust the filter to see more ApplicationSets.": "Adjust the filter to see more ApplicationSets.", - "There are no Argo CD ApplicationSets in this project.": "There are no Argo CD ApplicationSets in this project.", - "There are no Argo CD ApplicationSets in all projects.": "There are no Argo CD ApplicationSets in all projects.", - "No matching Argo CD ApplicationSets": "No matching Argo CD ApplicationSets", - "No Argo CD ApplicationSets": "No Argo CD ApplicationSets", - "There was an error retrieving applicationsets. Check your connection and reload the page.": "There was an error retrieving applicationsets. Check your connection and reload the page.", + "Create Rollout": "创建 Rollout", + "Pods": "Pod", + "Selector": "选择器", + "Rollout Status": "Rollout 状态", + "Revisions": "修订版", + "There was an error retrieving the rollout. Check your connection and reload the page.": "获取 Rollout 时出错。检查您的连接并重新载入页面。", + "There was an error retrieving the rollout revisions. Check your connection and reload the page.": "获取 rollout 修订时出错。检查您的连接并重新载入页面。", + "Active Service": "活跃服务", + "The active blue-green service": "活跃的 Blue-green 服务", + "Preview Service": "预览服务", + "The preview blue-green service": "预览 Blue-green 服务", + "ClusterAnalysis Template": "ClusterAnalysis 模板", + "Analysis Template": "分析模板", + "Stable Service": "稳定服务", + "The stable service": "稳定服务", + "Canary Service": "Canary 服务", + "The canary service": "Canary 服务", + "Analysis Templates": "分析模板", + "The analysis and cluster-scoped analysis templates used for the canary strategy": "用于 Canary 策略的分析和集群范围的分析模板", + "Topology view": "拓扑视图", + "No Argo CD Applications": "没有 Argo CD 应用程序", + "Loading Argo CD Applications...": "加载 Argo CD 应用...", + "No Argo CD Applications match the filter": "没有符合筛选条件的 Argo CD 应用程序", + "Adjust the filter to see more applications.": "调整筛选条件以查看更多应用程序。", + "There are no Argo CD Applications in this application set.": "此应用程序集中没有 Argo CD 应用程序。", + "There are no Argo CD Applications in all projects.": "所有项目中都没有 Argo CD 应用程序。", + "There are no Argo CD Applications in this project.": "此项目中没有 Argo CD 应用程序。", + "There was an error retrieving applications. Check your connection and reload the page.": "获取应用程序时出错。检查您的连接并重新载入页面。", + "ApplicationSet Applications": "ApplicationSet 应用程序", + "The graph and table views show the ApplicationSet's applications. Use the filter to filter applications based on their health and sync status.": "图形和表视图显示 ApplicationSet 的应用程序。使用筛选条件,根据应用的健康状态和同步状态进行筛选。", + "Revision": "版本", + "No Argo CD ApplicationSets match the filter": "没有符合筛选条件的 Argo CD ApplicationSet", + "Adjust the filter to see more ApplicationSets.": "调整筛选条件以查看更多 ApplicationSet。", + "There are no Argo CD ApplicationSets in this project.": "此项目中没有 Argo CD ApplicationSets。", + "There are no Argo CD ApplicationSets in all projects.": "所有项目中都没有 Argo CD ApplicationSets。", + "No matching Argo CD ApplicationSets": "没有匹配的 Argo CD ApplicationSet", + "No Argo CD ApplicationSets": "没有 Argo CD ApplicationSets", + "There was an error retrieving applicationsets. Check your connection and reload the page.": "获取应用程序时出错。检查您的连接并重新载入页面。", "ApplicationSets": "ApplicationSets", - "Create ApplicationSet": "Create ApplicationSet", - "No labels": "No labels", - "Namespace defines the space within which each name must be unique.": "Namespace defines the space within which each name must be unique.", - "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "Map of string keys and values that can be used to organize and categorize (scope and select) objects.", - "Edit": "Edit", - "Annotations": "Annotations", - "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.", - "Created at": "Created at", - "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.", - "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.", - "List view": "List view", - "Graph view": "Graph view", - "Sync": "Sync", - "Stop": "Stop", - "Refresh": "Refresh", - "Refresh (Hard)": "Refresh (Hard)", - "Actions": "Actions", - "You don't have permission to perform this action": "You don't have permission to perform this action", - "annotations": "annotations", - "annotation": "annotation", - "No owner": "No owner", + "Create ApplicationSet": "创建 ApplicationSet", + "No labels": "没有标签", + "Namespace defines the space within which each name must be unique.": "命名空间定义了一个空间,其中的每个名称必须是唯一的。", + "Map of string keys and values that can be used to organize and categorize (scope and select) objects.": "用于组织和分类(范围和选择)对象的字符串键和值映射。", + "Edit": "编辑", + "Annotations": "注解", + "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects.": "注解是一个无结构的键值映射,资源可由外部工具存储和检索任意元数据。它们不可查询,并在修改对象时被保留。", + "Created at": "创建于", + "Time is a wrapper around time. Time which supports correct marshaling to YAML and JSON.": "Time 是对 time 的封装。支持正确进行 YAML 和 JSON 编组的 Time 类型。", + "Owner references link this resource to its parent object. For example, Applications generated by an ApplicationSet will have that ApplicationSet as their owner. This relationship enables proper resource lifecycle management and garbage collection.": "所有者引用将此资源关联到其父对象。例如,一个 ApplicationSet 生成的应用程序会将 ApplicationSet 作为所有者。这种关联关系可实现正确的资源生命周期管理和垃圾回收。", "Pagination": "Pagination", "Go to first page": "Go to first page", "Go to previous page": "Go to previous page", @@ -360,5 +349,16 @@ "Go to last page": "Go to last page", "Items per page": "Items per page", "per page": "per page", - "of": "of" + "of": "of", + "List view": "列表视图", + "Graph view": "图形视图", + "Sync": "同步", + "Stop": "停止", + "Refresh": "刷新", + "Refresh (Hard)": "刷新(强制)", + "Actions": "行动", + "You don't have permission to perform this action": "您没有执行此操作的权限", + "annotations": "注解", + "annotation": "注解", + "No owner": "没有所有者" } diff --git a/locales/zh/plugin__gitops-public.json b/locales/zh/plugin__gitops-public.json index f0284a431..5a381137b 100644 --- a/locales/zh/plugin__gitops-public.json +++ b/locales/zh/plugin__gitops-public.json @@ -1,28 +1,28 @@ { - "Error": "Error", - "Receiving Traffic": "Receiving Traffic", - "Not Receiving Traffic": "Not Receiving Traffic", - "View logs": "View logs", - "Open URL": "Open URL", - "Edit": "Edit", + "Error": "错误", + "Receiving Traffic": "接收流量", + "Not Receiving Traffic": "非接收流量", + "View logs": "查看日志", + "Open URL": "打开 URI", + "Edit": "编辑", "Rollout": "Rollout", - "Name": "Name", - "Namespace": "Namespace", - "Annotations": "Annotations", - "No annotations": "No annotations", - "Labels": "Labels", - "No labels": "No labels", - "Update Strategy": "Update Strategy", - "Replicas": "Replicas", - "Revision History Limit": "Revision History Limit", - "True": "True", - "False": "False", - "Type": "Type", - "Status": "Status", - "Updated": "Updated", - "Reason": "Reason", - "Message": "Message", - "No conditions found": "No conditions found", - "No owner": "No owner", - "View {{kind}}": "View {{kind}}" + "Name": "名称", + "Namespace": "命名空间", + "Annotations": "注解", + "No annotations": "没有注解", + "Labels": "标签", + "No labels": "没有标签", + "Update Strategy": "更新策略", + "Replicas": "副本", + "Revision History Limit": "版本修订历史", + "True": "真", + "False": "假", + "Type": "类型", + "Status": "状态", + "Updated": "已更新", + "Reason": "原因", + "Message": "消息", + "No conditions found": "未找到条件", + "No owner": "没有所有者", + "View {{kind}}": "查看 {{kind}}" }