From 7163812c4b3a70679b0efb347e11b52c3f9948cb Mon Sep 17 00:00:00 2001 From: agatha197 Date: Thu, 10 Oct 2024 19:50:56 +0900 Subject: [PATCH] feat: fetch container registries with new nodes query --- react/data/schema.graphql | 450 +++++++++++++- .../ContainerRegistryEditorModal.tsx | 237 ++++---- ...ContainerRegistryEditorModalBefore2409.tsx | 411 +++++++++++++ .../src/components/ContainerRegistryList.tsx | 201 +++++-- .../ContainerRegistryListBefore2409.tsx | 569 ++++++++++++++++++ react/src/pages/EnvironmentPage.tsx | 13 +- resources/i18n/de.json | 5 +- resources/i18n/el.json | 5 +- resources/i18n/en.json | 5 +- resources/i18n/es.json | 5 +- resources/i18n/fi.json | 5 +- resources/i18n/fr.json | 5 +- resources/i18n/id.json | 5 +- resources/i18n/it.json | 5 +- resources/i18n/ja.json | 5 +- resources/i18n/ko.json | 5 +- resources/i18n/mn.json | 5 +- resources/i18n/ms.json | 5 +- resources/i18n/pl.json | 5 +- resources/i18n/pt-BR.json | 5 +- resources/i18n/pt.json | 5 +- resources/i18n/ru.json | 5 +- resources/i18n/th.json | 5 +- resources/i18n/tr.json | 5 +- resources/i18n/vi.json | 5 +- resources/i18n/zh-CN.json | 5 +- resources/i18n/zh-TW.json | 5 +- 27 files changed, 1787 insertions(+), 199 deletions(-) create mode 100644 react/src/components/ContainerRegistryEditorModalBefore2409.tsx create mode 100644 react/src/components/ContainerRegistryListBefore2409.tsx diff --git a/react/data/schema.graphql b/react/data/schema.graphql index fce2752fdf..18912ef865 100644 --- a/react/data/schema.graphql +++ b/react/data/schema.graphql @@ -97,13 +97,53 @@ type Queries { vfolder_node(id: String!): VirtualFolderNode """Added in 24.03.4.""" - vfolder_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): VirtualFolderConnection + vfolder_nodes( + """Added in 24.09.0.""" + project_id: UUID! + + """Added in 24.09.0.""" + permission: VFolderPermissionValueField + filter: String + order: String + offset: Int + before: String + after: String + first: Int + last: Int + ): VirtualFolderConnection vfolder_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, group_id: UUID, access_key: String): VirtualFolderList vfolder_permission_list(limit: Int!, offset: Int!, filter: String, order: String): VirtualFolderPermissionList vfolder_own_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, access_key: String): VirtualFolderList vfolder_invited_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, access_key: String): VirtualFolderList vfolder_project_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, access_key: String): VirtualFolderList vfolders(domain_name: String, group_id: String, access_key: String): [VirtualFolder] + + """Added in 24.09.0.""" + compute_session_node( + id: GlobalIDField! + + """Added in 24.09.0.""" + project_id: UUID! + + """Added in 24.09.0. Default is read_attribute.""" + permission: SessionPermissionValueField = "read_attribute" + ): ComputeSessionNode + + """Added in 24.09.0.""" + compute_session_nodes( + """Added in 24.09.0.""" + project_id: UUID! + + """Added in 24.09.0. Default is read_attribute.""" + permission: SessionPermissionValueField = "read_attribute" + filter: String + order: String + offset: Int + before: String + after: String + first: Int + last: Int + ): ComputeSessionConnection compute_session(id: UUID!): ComputeSession compute_container(id: UUID!): ComputeContainer compute_session_list(limit: Int!, offset: Int!, filter: String, order: String, domain_name: String, group_id: String, access_key: String, status: String): ComputeSessionList @@ -121,6 +161,12 @@ type Queries { container_registry(hostname: String!): ContainerRegistry container_registries: [ContainerRegistry] + """Added in 24.09.0.""" + container_registry_node(id: String!): ContainerRegistryNode + + """Added in 24.09.0.""" + container_registry_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): ContainerRegistryConnection + """Added in 24.03.0.""" model_card(id: String!): ModelCard @@ -242,6 +288,9 @@ type ImageNode implements Node { """Added in 24.03.4. The undecoded id value stored in DB.""" row_id: UUID name: String + + """Added in 24.03.10.""" + project: String humanized_name: String tag: String registry: String @@ -339,6 +388,7 @@ type GroupNode implements Node { user_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): UserConnection } +"""Added in 24.03.0""" type UserConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -367,7 +417,7 @@ type PageInfo { endCursor: String } -"""A Relay edge containing a `User` and its cursor.""" +"""Added in 24.03.0 A Relay edge containing a `User` and its cursor.""" type UserEdge { """The item at the end of the edge""" node: UserNode @@ -410,6 +460,7 @@ type UserNode implements Node { sudo_session_enabled: Boolean } +"""Added in 24.03.0""" type GroupConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -421,7 +472,7 @@ type GroupConnection { count: Int } -"""A Relay edge containing a `Group` and its cursor.""" +"""Added in 24.03.0 A Relay edge containing a `Group` and its cursor.""" type GroupEdge { """The item at the end of the edge""" node: GroupNode @@ -454,6 +505,9 @@ type Group { type Image { id: UUID name: String + + """Added in 24.03.10.""" + project: String humanized_name: String tag: String registry: String @@ -569,6 +623,9 @@ type ComputeSession implements Item { name: String type: String main_kernel_role: String + + """Added in 24.09.0.""" + priority: Int image: String architecture: String registry: String @@ -753,7 +810,7 @@ type StorageVolumeList implements PaginatedList { total_count: Int! } -"""Added in 24.03.4.""" +"""Added in 24.03.4""" type VirtualFolderNode implements Node { """The ID of the object""" id: ID! @@ -780,8 +837,19 @@ type VirtualFolderNode implements Node { cur_size: BigInt cloneable: Boolean status: String + + """ + Added in 24.09.0. One of ['clone', 'assign_permission_to_others', 'read_attribute', 'update_attribute', 'delete_vfolder', 'read_content', 'write_content', 'delete_content', 'mount_ro', 'mount_rw', 'mount_wd']. + """ + permissions: [VFolderPermissionValueField] } +""" +Added in 24.09.0. One of ['clone', 'assign_permission_to_others', 'read_attribute', 'update_attribute', 'delete_vfolder', 'read_content', 'write_content', 'delete_content', 'mount_ro', 'mount_rw', 'mount_wd']. +""" +scalar VFolderPermissionValueField + +"""Added in 24.03.4""" type VirtualFolderConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -793,7 +861,9 @@ type VirtualFolderConnection { count: Int } -"""A Relay edge containing a `VirtualFolder` and its cursor.""" +""" +Added in 24.03.4 A Relay edge containing a `VirtualFolder` and its cursor. +""" type VirtualFolderEdge { """The item at the end of the edge""" node: VirtualFolderNode @@ -821,6 +891,150 @@ type VirtualFolderPermission implements Item { user_email: String } +"""Added in 24.09.0.""" +type ComputeSessionNode implements Node { + """The ID of the object""" + id: ID! + + """ID of session.""" + row_id: UUID + tag: String + name: String + type: String + + """Added in 24.09.0.""" + priority: Int + cluster_template: String + cluster_mode: String + cluster_size: Int + domain_name: String + project_id: UUID + user_id: UUID + access_key: String + + """ + One of ['read_attribute', 'update_attribute', 'delete_session', 'start_app', 'execute', 'convert_to_image']. + """ + permissions: [SessionPermissionValueField] + status: String + status_info: String + status_data: JSONString + status_history: JSONString + created_at: DateTime + terminated_at: DateTime + starts_at: DateTime + scheduled_at: DateTime + startup_command: String + result: String + commit_status: String + abusing_reports: [JSONString] + idle_checks: JSONString + agent_ids: [String] + resource_opts: JSONString + scaling_group: String + service_ports: JSONString + vfolder_mounts: [String] + occupied_slots: JSONString + requested_slots: JSONString + num_queries: BigInt + inference_metrics: JSONString + kernel_nodes(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): KernelConnection + + """Added in 24.09.0.""" + dependents(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): ComputeSessionConnection + + """Added in 24.09.0.""" + dependees(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): ComputeSessionConnection + + """Added in 24.09.0.""" + graph(filter: String, order: String, offset: Int, before: String, after: String, first: Int, last: Int): ComputeSessionConnection +} + +""" +Added in 24.09.0. One of ['read_attribute', 'update_attribute', 'delete_session', 'start_app', 'execute', 'convert_to_image']. +""" +scalar SessionPermissionValueField + +"""Added in 24.09.0.""" +type KernelConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [KernelEdge]! + + """Total count of the GQL nodes of the query.""" + count: Int +} + +"""Added in 24.09.0. A Relay edge containing a `Kernel` and its cursor.""" +type KernelEdge { + """The item at the end of the edge""" + node: KernelNode + + """A cursor for use in pagination""" + cursor: String! +} + +"""Added in 24.09.0.""" +type KernelNode implements Node { + """The ID of the object""" + id: ID! + + """ID of kernel.""" + row_id: UUID + cluster_idx: Int + local_rank: Int + cluster_role: String + cluster_hostname: String + session_id: UUID + image: ImageNode + status: String + status_changed: DateTime + status_info: String + status_data: JSONString + created_at: DateTime + terminated_at: DateTime + starts_at: DateTime + scheduled_at: DateTime + agent_id: String + agent_addr: String + container_id: String + resource_opts: JSONString + occupied_slots: JSONString + live_stat: JSONString + abusing_report: JSONString + preopen_ports: [Int] +} + +"""Added in 24.09.0.""" +type ComputeSessionConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ComputeSessionEdge]! + + """Total count of the GQL nodes of the query.""" + count: Int +} + +""" +Added in 24.09.0. A Relay edge containing a `ComputeSession` and its cursor. +""" +type ComputeSessionEdge { + """The item at the end of the edge""" + node: ComputeSessionNode + + """A cursor for use in pagination""" + cursor: String! +} + +""" +Added in 24.09.0. Global ID of GQL relay spec. Base64 encoded version of ":". UUID or string type values are also allowed. +""" +scalar GlobalIDField + type ComputeSessionList implements PaginatedList { items: [ComputeSession]! total_count: Int! @@ -1034,6 +1248,71 @@ type ContainerRegistryConfig { username: String password: String ssl_verify: Boolean + + """Added in 24.09.0.""" + is_global: Boolean +} + +"""Added in 24.09.0.""" +type ContainerRegistryNode implements Node { + """The ID of the object""" + id: ID! + + """ + Added in 24.09.0. The undecoded UUID type id of DB container_registries row. + """ + row_id: UUID + name: String + + """Added in 24.09.0.""" + url: String! + + """Added in 24.09.0.""" + type: ContainerRegistryTypeField! + + """Added in 24.09.0.""" + registry_name: String! + + """Added in 24.09.0.""" + is_global: Boolean + + """Added in 24.09.0.""" + project: String + + """Added in 24.09.0.""" + username: String + + """Added in 24.09.0.""" + password: String + + """Added in 24.09.0.""" + ssl_verify: Boolean +} + +"""Added in 24.09.0.""" +scalar ContainerRegistryTypeField + +"""Added in 24.09.0.""" +type ContainerRegistryConnection { + """Pagination data for this connection.""" + pageInfo: PageInfo! + + """Contains the nodes in this connection.""" + edges: [ContainerRegistryEdge]! + + """Total count of the GQL nodes of the query.""" + count: Int +} + +""" +Added in 24.09.0. A Relay edge containing a `ContainerRegistry` and its cursor. +""" +type ContainerRegistryEdge { + """The item at the end of the edge""" + node: ContainerRegistryNode + + """A cursor for use in pagination""" + cursor: String! } type ModelCard implements Node { @@ -1077,6 +1356,7 @@ type ModelCard implements Node { error_msg: String } +"""Added in 24.03.4""" type ModelCardConnection { """Pagination data for this connection.""" pageInfo: PageInfo! @@ -1088,7 +1368,7 @@ type ModelCardConnection { count: Int } -"""A Relay edge containing a `ModelCard` and its cursor.""" +"""Added in 24.03.4 A Relay edge containing a `ModelCard` and its cursor.""" type ModelCardEdge { """The item at the end of the edge""" node: ModelCard @@ -1169,6 +1449,9 @@ type Mutations { alias_image(alias: String!, architecture: String = "x86_64", target: String!): AliasImage dealias_image(alias: String!): DealiasImage clear_images(registry: String): ClearImages + + """Added in 24.09.0.""" + modify_compute_session(input: ModifyComputeSessionInput!): ModifyComputeSessionPayload create_keypair_resource_policy(name: String!, props: CreateKeyPairResourcePolicyInput!): CreateKeyPairResourcePolicy modify_keypair_resource_policy(name: String!, props: ModifyKeyPairResourcePolicyInput!): ModifyKeyPairResourcePolicy delete_keypair_resource_policy(name: String!): DeleteKeyPairResourcePolicy @@ -1185,15 +1468,100 @@ type Mutations { modify_scaling_group(name: String!, props: ModifyScalingGroupInput!): ModifyScalingGroup delete_scaling_group(name: String!): DeleteScalingGroup associate_scaling_group_with_domain(domain: String!, scaling_group: String!): AssociateScalingGroupWithDomain + + """Added in 24.03.9""" + associate_scaling_groups_with_domain(domain: String!, scaling_groups: [String]!): AssociateScalingGroupsWithDomain associate_scaling_group_with_user_group(scaling_group: String!, user_group: UUID!): AssociateScalingGroupWithUserGroup + + """Added in 24.03.9""" + associate_scaling_groups_with_user_group(scaling_groups: [String]!, user_group: UUID!): AssociateScalingGroupsWithUserGroup associate_scaling_group_with_keypair(access_key: String!, scaling_group: String!): AssociateScalingGroupWithKeyPair + + """Added in 24.03.9""" + associate_scaling_groups_with_keypair(access_key: String!, scaling_groups: [String]!): AssociateScalingGroupsWithKeyPair disassociate_scaling_group_with_domain(domain: String!, scaling_group: String!): DisassociateScalingGroupWithDomain + + """Added in 24.03.9""" + disassociate_scaling_groups_with_domain(domain: String!, scaling_groups: [String]!): DisassociateScalingGroupsWithDomain disassociate_scaling_group_with_user_group(scaling_group: String!, user_group: UUID!): DisassociateScalingGroupWithUserGroup + + """Added in 24.03.9""" + disassociate_scaling_groups_with_user_group(scaling_groups: [String]!, user_group: UUID!): DisassociateScalingGroupsWithUserGroup disassociate_scaling_group_with_keypair(access_key: String!, scaling_group: String!): DisassociateScalingGroupWithKeyPair + + """Added in 24.03.9""" + disassociate_scaling_groups_with_keypair(access_key: String!, scaling_groups: [String]!): DisassociateScalingGroupsWithKeyPair disassociate_all_scaling_groups_with_domain(domain: String!): DisassociateAllScalingGroupsWithDomain disassociate_all_scaling_groups_with_group(user_group: UUID!): DisassociateAllScalingGroupsWithGroup set_quota_scope(props: QuotaScopeInput!, quota_scope_id: String!, storage_host_name: String!): SetQuotaScope unset_quota_scope(quota_scope_id: String!, storage_host_name: String!): UnsetQuotaScope + + """Added in 24.09.0.""" + create_container_registry_node( + """Added in 24.09.0.""" + is_global: Boolean + + """Added in 24.09.0.""" + password: String + + """Added in 24.09.0.""" + project: String + + """Added in 24.09.0.""" + registry_name: String! + + """Added in 24.09.0.""" + ssl_verify: Boolean + + """ + Added in 24.09.0. Registry type. One of ('docker', 'harbor', 'harbor2', 'github', 'gitlab', 'ecr', 'ecr-public', 'local'). + """ + type: ContainerRegistryTypeField! + + """Added in 24.09.0.""" + url: String! + + """Added in 24.09.0.""" + username: String + ): CreateContainerRegistryNode + + """Added in 24.09.0.""" + modify_container_registry_node( + """Object id. Can be either global id or object id. Added in 24.09.0.""" + id: String! + + """Added in 24.09.0.""" + is_global: Boolean + + """Added in 24.09.0.""" + password: String + + """Added in 24.09.0.""" + project: String + + """Added in 24.09.0.""" + registry_name: String + + """Added in 24.09.0.""" + ssl_verify: Boolean + + """ + Registry type. One of ('docker', 'harbor', 'harbor2', 'github', 'gitlab', 'ecr', 'ecr-public', 'local'). Added in 24.09.0. + """ + type: ContainerRegistryTypeField + + """Added in 24.09.0.""" + url: String + + """Added in 24.09.0.""" + username: String + ): ModifyContainerRegistryNode + + """Added in 24.09.0.""" + delete_container_registry_node( + """Object id. Can be either global id or object id. Added in 24.09.0.""" + id: String! + ): DeleteContainerRegistryNode create_container_registry(hostname: String!, props: CreateContainerRegistryInput!): CreateContainerRegistry modify_container_registry(hostname: String!, props: ModifyContainerRegistryInput!): ModifyContainerRegistry delete_container_registry(hostname: String!): DeleteContainerRegistry @@ -1521,6 +1889,19 @@ type ClearImages { msg: String } +"""Added in 24.09.0.""" +type ModifyComputeSessionPayload { + item: ComputeSessionNode + clientMutationId: String +} + +input ModifyComputeSessionInput { + id: GlobalIDField! + name: String + priority: Int + clientMutationId: String +} + type CreateKeyPairResourcePolicy { ok: Boolean msg: String @@ -1753,31 +2134,67 @@ type AssociateScalingGroupWithDomain { msg: String } +"""Added in 24.03.9.""" +type AssociateScalingGroupsWithDomain { + ok: Boolean + msg: String +} + type AssociateScalingGroupWithUserGroup { ok: Boolean msg: String } +"""Added in 24.03.9.""" +type AssociateScalingGroupsWithUserGroup { + ok: Boolean + msg: String +} + type AssociateScalingGroupWithKeyPair { ok: Boolean msg: String } +"""Added in 24.03.9.""" +type AssociateScalingGroupsWithKeyPair { + ok: Boolean + msg: String +} + type DisassociateScalingGroupWithDomain { ok: Boolean msg: String } +"""Added in 24.03.9.""" +type DisassociateScalingGroupsWithDomain { + ok: Boolean + msg: String +} + type DisassociateScalingGroupWithUserGroup { ok: Boolean msg: String } +"""Added in 24.03.9.""" +type DisassociateScalingGroupsWithUserGroup { + ok: Boolean + msg: String +} + type DisassociateScalingGroupWithKeyPair { ok: Boolean msg: String } +"""Added in 24.03.9.""" +type DisassociateScalingGroupsWithKeyPair { + ok: Boolean + msg: String +} + type DisassociateAllScalingGroupsWithDomain { ok: Boolean msg: String @@ -1800,6 +2217,21 @@ type UnsetQuotaScope { quota_scope: QuotaScope } +"""Added in 24.09.0.""" +type CreateContainerRegistryNode { + container_registry: ContainerRegistryNode +} + +"""Added in 24.09.0.""" +type ModifyContainerRegistryNode { + container_registry: ContainerRegistryNode +} + +"""Added in 24.09.0.""" +type DeleteContainerRegistryNode { + container_registry: ContainerRegistryNode +} + type CreateContainerRegistry { container_registry: ContainerRegistry } @@ -1811,6 +2243,9 @@ input CreateContainerRegistryInput { username: String password: String ssl_verify: Boolean + + """Added in 24.09.0.""" + is_global: Boolean } type ModifyContainerRegistry { @@ -1824,6 +2259,9 @@ input ModifyContainerRegistryInput { username: String password: String ssl_verify: Boolean + + """Added in 24.09.0.""" + is_global: Boolean } type DeleteContainerRegistry { diff --git a/react/src/components/ContainerRegistryEditorModal.tsx b/react/src/components/ContainerRegistryEditorModal.tsx index a04b3c0e17..a012859e96 100644 --- a/react/src/components/ContainerRegistryEditorModal.tsx +++ b/react/src/components/ContainerRegistryEditorModal.tsx @@ -1,4 +1,5 @@ import BAIModal, { BAIModalProps } from './BAIModal'; +import HiddenFormItem from './HiddenFormItem'; import { ContainerRegistryEditorModalCreateMutation } from './__generated__/ContainerRegistryEditorModalCreateMutation.graphql'; import { ContainerRegistryEditorModalFragment$key } from './__generated__/ContainerRegistryEditorModalFragment.graphql'; import { ContainerRegistryEditorModalModifyMutation } from './__generated__/ContainerRegistryEditorModalModifyMutation.graphql'; @@ -11,14 +12,14 @@ import { useFragment, useMutation } from 'react-relay'; interface ContainerRegistryEditorModalProps extends Omit { - existingHostnames?: string[]; + existingRegistryNames?: string[]; onOk: (type: 'create' | 'modify') => void; containerRegistryFrgmt?: ContainerRegistryEditorModalFragment$key | null; } const ContainerRegistryEditorModal: React.FC< ContainerRegistryEditorModalProps > = ({ - existingHostnames, + existingRegistryNames, containerRegistryFrgmt = null, onOk, ...modalProps @@ -30,16 +31,16 @@ const ContainerRegistryEditorModal: React.FC< const containerRegistry = useFragment( graphql` - fragment ContainerRegistryEditorModalFragment on ContainerRegistry { + fragment ContainerRegistryEditorModalFragment on ContainerRegistryNode { id - hostname - config { - url - type - project - username - ssl_verify - } + row_id + name + registry_name + url + type + project + username + ssl_verify } `, containerRegistryFrgmt, @@ -47,21 +48,27 @@ const ContainerRegistryEditorModal: React.FC< const [commitCreateRegistry, isInflightCreateRegistry] = useMutation(graphql` mutation ContainerRegistryEditorModalCreateMutation( - $hostname: String! - $props: CreateContainerRegistryInput! + $registry_name: String! + $type: ContainerRegistryTypeField! + $url: String! + $is_global: Boolean + $password: String + $project: String + $ssl_verify: Boolean + $username: String ) { - create_container_registry(hostname: $hostname, props: $props) { + create_container_registry_node( + registry_name: $registry_name + type: $type + url: $url + is_global: $is_global + password: $password + project: $project + ssl_verify: $ssl_verify + username: $username + ) { container_registry { id - hostname - config { - url - type - project - username - password - ssl_verify - } } } } @@ -70,21 +77,29 @@ const ContainerRegistryEditorModal: React.FC< const [commitModifyRegistry, isInflightModifyRegistry] = useMutation(graphql` mutation ContainerRegistryEditorModalModifyMutation( - $hostname: String! - $props: ModifyContainerRegistryInput! + $id: String! + $registry_name: String + $type: ContainerRegistryTypeField + $url: String + $is_global: Boolean + $password: String + $project: String + $ssl_verify: Boolean + $username: String ) { - modify_container_registry(hostname: $hostname, props: $props) { + modify_container_registry_node( + id: $id + registry_name: $registry_name + type: $type + url: $url + is_global: $is_global + password: $password + project: $project + ssl_verify: $ssl_verify + username: $username + ) { container_registry { id - hostname - config { - url - type - project - username - password - ssl_verify - } } } } @@ -94,34 +109,33 @@ const ContainerRegistryEditorModal: React.FC< return formRef.current ?.validateFields() .then((values) => { - const mutationVariables = { - hostname: values.hostname, - props: { - url: values.config.url, - type: values.config.type, - project: - values.config.project === 'docker' - ? undefined - : values.config.project, - username: _.isEmpty(values.config.username) - ? null - : values.config.username, - password: values.isChangedPassword - ? _.isEmpty(values.config.password) - ? null // unset - : values.config.password - : undefined, // no change - }, + let mutationVariables = { + id: _.isEmpty(values.row_id) ? undefined : values.row_id, + registry_name: values.registry_name, + url: values.url, + type: values.type, + project: values.type === 'docker' ? 'library' : values.project, + username: _.isEmpty(values.username) ? null : values.username, + password: values.isChangedPassword + ? _.isEmpty(values.password) + ? null // unset + : values.password + : undefined, // no change }; if (containerRegistry) { if (!values.isChangedPassword) { - delete mutationVariables.props.password; + delete mutationVariables.password; } + mutationVariables = _.omitBy(mutationVariables, _.isNil) as Required< + typeof mutationVariables + >; commitModifyRegistry({ variables: mutationVariables, onCompleted: (res, errors) => { if ( - _.isEmpty(res.modify_container_registry?.container_registry) + _.isEmpty( + res.modify_container_registry_node?.container_registry, + ) ) { message.error(t('dialog.ErrorOccurred')); return; @@ -140,11 +154,16 @@ const ContainerRegistryEditorModal: React.FC< }, }); } else { + mutationVariables = _.omitBy(mutationVariables, _.isNil) as Required< + typeof mutationVariables + >; commitCreateRegistry({ variables: mutationVariables, onCompleted: (res, errors) => { if ( - _.isEmpty(res?.create_container_registry?.container_registry) + _.isEmpty( + res?.create_container_registry_node?.container_registry, + ) ) { message.error(t('dialog.ErrorOccurred')); return; @@ -180,12 +199,11 @@ const ContainerRegistryEditorModal: React.FC< ?.validateFields() .then((values) => { if ( - _.includes(values.config?.type, 'harbor') && - (_.isEmpty(values.config.username) || + _.includes(values?.type, 'harbor') && + (_.isEmpty(values.username) || (containerRegistry - ? values.isChangedPassword && - _.isEmpty(values.config.password) - : _.isEmpty(values.config.password))) + ? values.isChangedPassword && _.isEmpty(values.password) + : _.isEmpty(values.password))) ) { modal.confirm({ title: t('button.Confirm'), @@ -211,34 +229,34 @@ const ContainerRegistryEditorModal: React.FC< containerRegistry ? { ...containerRegistry, - config: { - ...containerRegistry.config, - project: containerRegistry.config?.project || undefined, - }, } : { - config: { - type: 'docker', - }, + type: 'docker', } } preserve={false} > + {containerRegistry && ( + + )} { - if (!containerRegistry && existingHostnames?.includes(value)) { + if ( + !containerRegistry && + existingRegistryNames?.includes(value) + ) { return Promise.reject( - t('registry.RegistryHostnameAlreadyExists'), + t('registry.RegistryNameAlreadyExists'), ); } return Promise.resolve(); @@ -248,12 +266,12 @@ const ContainerRegistryEditorModal: React.FC< > - _.isEmpty(prev.config?.password) !== - _.isEmpty(next.config?.password) + _.isEmpty(prev?.password) !== _.isEmpty(next?.password) } > {({ validateFields, getFieldValue }) => { - validateFields([['config', 'username']]); + validateFields(['username']); return ( @@ -315,7 +332,7 @@ const ContainerRegistryEditorModal: React.FC< } > {({ getFieldValue }) => ( - + { if (!e.target.checked) { - formRef.current?.setFieldValue(['config', 'password'], ''); + formRef.current?.setFieldValue('password', ''); } }} > @@ -340,7 +357,7 @@ const ContainerRegistryEditorModal: React.FC< )} { - // form.validateFields(); + onChange={(value) => { + if (value === 'docker') { + formRef.current?.setFieldValue('project', 'library'); + formRef.current?.validateFields(['project']); + } }} > - prev?.config?.type !== next?.config?.type - } + shouldUpdate={(prev, next) => prev?.type !== next?.type} noStyle > {({ getFieldValue }) => { return ( - getFieldValue(['config', 'type']) !== 'docker' && ( - - {/* */} - + ); }} diff --git a/react/src/components/ContainerRegistryEditorModalBefore2409.tsx b/react/src/components/ContainerRegistryEditorModalBefore2409.tsx new file mode 100644 index 0000000000..727ba002e4 --- /dev/null +++ b/react/src/components/ContainerRegistryEditorModalBefore2409.tsx @@ -0,0 +1,411 @@ +import BAIModal, { BAIModalProps } from './BAIModal'; +import { ContainerRegistryEditorModalBefore2409CreateMutation } from './__generated__/ContainerRegistryEditorModalBefore2409CreateMutation.graphql'; +import { ContainerRegistryEditorModalBefore2409Fragment$key } from './__generated__/ContainerRegistryEditorModalBefore2409Fragment.graphql'; +import { ContainerRegistryEditorModalBefore2409ModifyMutation } from './__generated__/ContainerRegistryEditorModalBefore2409ModifyMutation.graphql'; +import { Form, Input, Select, Checkbox, FormInstance, App } from 'antd'; +import graphql from 'babel-plugin-relay/macro'; +import _ from 'lodash'; +import React, { useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useFragment, useMutation } from 'react-relay'; + +interface ContainerRegistryEditorModalBefore2409Props + extends Omit { + existingHostnames?: string[]; + onOk: (type: 'create' | 'modify') => void; + containerRegistryFrgmt?: ContainerRegistryEditorModalBefore2409Fragment$key | null; +} +const ContainerRegistryEditorModal: React.FC< + ContainerRegistryEditorModalBefore2409Props +> = ({ + existingHostnames, + containerRegistryFrgmt = null, + onOk, + ...modalProps +}) => { + const { t } = useTranslation(); + const formRef = useRef(null); + + const { message, modal } = App.useApp(); + + const containerRegistry = useFragment( + graphql` + fragment ContainerRegistryEditorModalBefore2409Fragment on ContainerRegistry { + id + hostname + config { + url + type + project + username + ssl_verify + } + } + `, + containerRegistryFrgmt, + ); + const [commitCreateRegistry, isInflightCreateRegistry] = + useMutation(graphql` + mutation ContainerRegistryEditorModalBefore2409CreateMutation( + $hostname: String! + $props: CreateContainerRegistryInput! + ) { + create_container_registry(hostname: $hostname, props: $props) { + container_registry { + id + hostname + config { + url + type + project + username + password + ssl_verify + } + } + } + } + `); + + const [commitModifyRegistry, isInflightModifyRegistry] = + useMutation(graphql` + mutation ContainerRegistryEditorModalBefore2409ModifyMutation( + $hostname: String! + $props: ModifyContainerRegistryInput! + ) { + modify_container_registry(hostname: $hostname, props: $props) { + container_registry { + id + hostname + config { + url + type + project + username + password + ssl_verify + } + } + } + } + `); + + const handleSave = async () => { + return formRef.current + ?.validateFields() + .then((values) => { + const mutationVariables = { + hostname: values.hostname, + props: { + url: values.config.url, + type: values.config.type, + project: + values.config.project === 'docker' + ? undefined + : values.config.project, + username: _.isEmpty(values.config.username) + ? null + : values.config.username, + password: values.isChangedPassword + ? _.isEmpty(values.config.password) + ? null // unset + : values.config.password + : undefined, // no change + }, + }; + if (containerRegistry) { + if (!values.isChangedPassword) { + delete mutationVariables.props.password; + } + commitModifyRegistry({ + variables: mutationVariables, + onCompleted: (res, errors) => { + if ( + _.isEmpty(res.modify_container_registry?.container_registry) + ) { + message.error(t('dialog.ErrorOccurred')); + return; + } + if (errors && errors.length > 0) { + const errorMsgList = _.map(errors, (error) => error.message); + for (const error of errorMsgList) { + message.error(error, 2.5); + } + } else { + onOk && onOk('modify'); + } + }, + onError: (error) => { + message.error(t('dialog.ErrorOccurred')); + }, + }); + } else { + commitCreateRegistry({ + variables: mutationVariables, + onCompleted: (res, errors) => { + if ( + _.isEmpty(res?.create_container_registry?.container_registry) + ) { + message.error(t('dialog.ErrorOccurred')); + return; + } + if (errors && errors?.length > 0) { + const errorMsgList = _.map(errors, (error) => error.message); + for (const error of errorMsgList) { + message.error(error, 2.5); + } + } else { + onOk && onOk('create'); + } + }, + onError(error) { + message.error(t('dialog.ErrorOccurred')); + }, + }); + } + }) + .catch((error) => {}); + }; + return ( + { + formRef.current + ?.validateFields() + .then((values) => { + if ( + _.includes(values.config?.type, 'harbor') && + (_.isEmpty(values.config.username) || + (containerRegistry + ? values.isChangedPassword && + _.isEmpty(values.config.password) + : _.isEmpty(values.config.password))) + ) { + modal.confirm({ + title: t('button.Confirm'), + content: t('registry.ConfirmNoUserName'), + onOk: () => { + handleSave(); + }, + }); + } else { + handleSave(); + } + }) + .catch(() => {}); + }} + {...modalProps} + destroyOnClose + > +
+ { + if (!containerRegistry && existingHostnames?.includes(value)) { + return Promise.reject( + t('registry.RegistryHostnameAlreadyExists'), + ); + } + return Promise.resolve(); + }, + }, + ]} + > + + + { + if (value) { + if ( + !value.startsWith('http://') && + !value.startsWith('https://') + ) + return Promise.reject(t('registry.DescURLStartString')); + try { + new URL(value); + } catch (e) { + return Promise.reject(t('registry.DescURLFormat')); + } + } + return Promise.resolve(); + }, + }, + ]} + > + + + + + _.isEmpty(prev.config?.password) !== + _.isEmpty(next.config?.password) + } + > + {({ validateFields, getFieldValue }) => { + validateFields([['config', 'username']]); + return ( + + + + ); + }} + + + + + prev.isChangedPassword !== next.isChangedPassword + } + > + {({ getFieldValue }) => ( + + + + )} + + {!_.isEmpty(containerRegistry) && ( + + { + if (!e.target.checked) { + formRef.current?.setFieldValue(['config', 'password'], ''); + } + }} + > + {t('webui.menu.ChangePassword')} + + + )} + + + + + + prev?.config?.type !== next?.config?.type + } + noStyle + > + {({ getFieldValue }) => { + return ( + getFieldValue(['config', 'type']) !== 'docker' && ( + + {/* */} + setDeletingConfirmText(e.target.value)} + /> + + + +
+ + ); +}; + +export default ContainerRegistryListBefore2409; diff --git a/react/src/pages/EnvironmentPage.tsx b/react/src/pages/EnvironmentPage.tsx index 0391f3a596..cc46d5368e 100644 --- a/react/src/pages/EnvironmentPage.tsx +++ b/react/src/pages/EnvironmentPage.tsx @@ -1,4 +1,5 @@ import ContainerRegistryList from '../components/ContainerRegistryList'; +import ContainerRegistryListBefore2409 from '../components/ContainerRegistryListBefore2409'; import FlexActivityIndicator from '../components/FlexActivityIndicator'; import ImageList from '../components/ImageList'; import ResourcePresetList from '../components/ResourcePresetList'; @@ -17,6 +18,8 @@ const EnvironmentPage = () => { const isSupportContainerRegistryGraphQL = baiClient.supports( 'container-registry-gql', ); + const isSupportContainerRegistryNodes = + baiClient?.isManagerVersionCompatibleWith('24.09.0'); return ( { {curTabKey === 'preset' && } {curTabKey === 'registry' ? ( isSupportContainerRegistryGraphQL ? ( - + isSupportContainerRegistryNodes ? ( + // manager ≤ v24.09.0 + + ) : ( + // v23.09.2 ≤ manager < v24.09.0 + + ) ) : ( + // TODO: remove this from 24.09.2 + // v23.09.2 < manager // @ts-ignore ) diff --git a/resources/i18n/de.json b/resources/i18n/de.json index af25679c49..3326261e9d 100644 --- a/resources/i18n/de.json +++ b/resources/i18n/de.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Keine Registrierungen anzeigen", "ModifyRegistry": "Registry ändern", "ConfirmNoUserName": "Benutzer und Passwort nicht angegeben, möchten Sie speichern?", - "DescURLFormat": "Ungültiger URL-Typ" + "DescURLFormat": "Ungültiger URL-Typ", + "RegistryName": "Registrierungsname", + "DescRegistryNameIsEmpty": "Der Registrierungsname ist leer", + "RegistryNameAlreadyExists": "Der Registrierungsname ist bereits vorhanden. \nBitte ändern Sie den hinzuzufügenden Registrierungsnamen." }, "resourceGroup": { "ResourceGroups": "Ressourcengruppen", diff --git a/resources/i18n/el.json b/resources/i18n/el.json index cee1365ccc..3d9d9f53cf 100644 --- a/resources/i18n/el.json +++ b/resources/i18n/el.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Δεν εμφανίζονται μητρώα", "ModifyRegistry": "Τροποποίηση μητρώου", "ConfirmNoUserName": "Ο χρήστης και ο κωδικός πρόσβασης δεν έχουν καθοριστεί, θέλετε να αποθηκεύσετε;", - "DescURLFormat": "Μη έγκυρος τύπος URL" + "DescURLFormat": "Μη έγκυρος τύπος URL", + "RegistryName": "Όνομα Μητρώου", + "DescRegistryNameIsEmpty": "Το όνομα μητρώου είναι κενό", + "RegistryNameAlreadyExists": "Το όνομα μητρώου υπάρχει ήδη. \nΑλλάξτε το όνομα μητρώου για προσθήκη." }, "resourceGroup": { "ResourceGroups": "Ομάδες πόρων", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 4a3cbc373c..f178ca78ec 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -1211,7 +1211,10 @@ "RegistrySuccessfullyModified": "Registry successfully modified.", "PleaseSelectOption": "Please Select Option", "ConfirmNoUserName": "User and password not specified, would you like to save?", - "DescURLFormat": "Invalid URL Type" + "DescURLFormat": "Invalid URL Type", + "RegistryName": "Registry Name", + "DescRegistryNameIsEmpty": "Registry name is empty", + "RegistryNameAlreadyExists": "Registry name already exists. Please change the registry name to add." }, "resourceGroup": { "ResourceGroups": "Resource Groups", diff --git a/resources/i18n/es.json b/resources/i18n/es.json index 489a07c790..439d06c1e3 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -917,7 +917,10 @@ "Username": "Nombre de usuario", "UsernameOptional": "Nombre de usuario (opcional)", "ConfirmNoUserName": "Usuario y contraseña no especificados, ¿desea guardar?", - "DescURLFormat": "Tipo de URL no válido" + "DescURLFormat": "Tipo de URL no válido", + "RegistryName": "Nombre de registro", + "DescRegistryNameIsEmpty": "El nombre del registro está vacío", + "RegistryNameAlreadyExists": "El nombre del registro ya existe. \nCambie el nombre del registro para agregar." }, "resourceGroup": { "Active": "Activo", diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json index 8fff1da6dc..3d8a2c548c 100644 --- a/resources/i18n/fi.json +++ b/resources/i18n/fi.json @@ -914,7 +914,10 @@ "Username": "Käyttäjätunnus", "UsernameOptional": "Käyttäjätunnus (valinnainen)", "ConfirmNoUserName": "Käyttäjää ja salasanaa ei ole määritetty, haluatko tallentaa?", - "DescURLFormat": "Virheellinen URL-tyyppi" + "DescURLFormat": "Virheellinen URL-tyyppi", + "RegistryName": "Rekisterin nimi", + "DescRegistryNameIsEmpty": "Rekisterin nimi on tyhjä", + "RegistryNameAlreadyExists": "Rekisterin nimi on jo olemassa. \nMuuta lisättävä rekisterinimi." }, "resourceGroup": { "Active": "Aktiivinen", diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index bef9c61277..3cb54777c8 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -1084,7 +1084,10 @@ "ModifyRegistry": "Modifier le registre", "NoRegistryToDisplay": "Aucun registre à afficher", "ConfirmNoUserName": "L'utilisateur et le mot de passe ne sont pas spécifiés, voulez-vous sauvegarder ?", - "DescURLFormat": "Type d'URL invalide" + "DescURLFormat": "Type d'URL invalide", + "RegistryName": "Nom du registre", + "DescRegistryNameIsEmpty": "Le nom du registre est vide", + "RegistryNameAlreadyExists": "Le nom du registre existe déjà. \nVeuillez modifier le nom du registre à ajouter." }, "resourceGroup": { "ResourceGroups": "Groupes de ressources", diff --git a/resources/i18n/id.json b/resources/i18n/id.json index 2e7d25cb27..8e80d5cd38 100644 --- a/resources/i18n/id.json +++ b/resources/i18n/id.json @@ -1085,7 +1085,10 @@ "ModifyRegistry": "Memodifikasi Registri", "NoRegistryToDisplay": "Tidak ada Pendaftaran untuk ditampilkan", "ConfirmNoUserName": "Pengguna dan kata sandi tidak ditentukan, apakah Anda ingin menyimpan?", - "DescURLFormat": "Jenis URL tidak valid" + "DescURLFormat": "Jenis URL tidak valid", + "RegistryName": "Nama Registri", + "DescRegistryNameIsEmpty": "Nama registri kosong", + "RegistryNameAlreadyExists": "Nama registri sudah ada. \nSilakan ubah nama registri untuk ditambahkan." }, "resourceGroup": { "ResourceGroups": "Grup Sumber Daya", diff --git a/resources/i18n/it.json b/resources/i18n/it.json index c025df134f..9db68610f7 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Nessun registro da visualizzare", "ModifyRegistry": "Modificare il registro", "ConfirmNoUserName": "Utente e password non specificati, si desidera salvare?", - "DescURLFormat": "Tipo di URL non valido" + "DescURLFormat": "Tipo di URL non valido", + "RegistryName": "Nome del registro", + "DescRegistryNameIsEmpty": "Il nome del registro è vuoto", + "RegistryNameAlreadyExists": "Il nome del registro esiste già. \nModificare il nome del registro da aggiungere." }, "resourceGroup": { "ResourceGroups": "Gruppi di risorse", diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json index f5969d8639..22ae379f7a 100644 --- a/resources/i18n/ja.json +++ b/resources/i18n/ja.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "レジストリ情報がありません。", "ModifyRegistry": "レジストリの修正", "ConfirmNoUserName": "ユーザーとパスワードが指定されていません。", - "DescURLFormat": "無効な URL タイプ" + "DescURLFormat": "無効な URL タイプ", + "RegistryName": "レジストリ名", + "DescRegistryNameIsEmpty": "レジストリ名が空です", + "RegistryNameAlreadyExists": "レジストリ名はすでに存在します。\n追加するレジストリ名を変更してください。" }, "resourceGroup": { "ResourceGroups": "リソースグループ", diff --git a/resources/i18n/ko.json b/resources/i18n/ko.json index 4da982ba19..778aff482f 100644 --- a/resources/i18n/ko.json +++ b/resources/i18n/ko.json @@ -1197,7 +1197,10 @@ "RegistrySuccessfullyModified": "레지스트리가 성공적으로 수정되었습니다.", "PleaseSelectOption": "옵션을 선택하세요", "ConfirmNoUserName": "사용자 및 비밀번호가 지정되지 않았습니다. 저장하시겠습니까?", - "DescURLFormat": "올바르지 않는 URL 타입입니다." + "DescURLFormat": "올바르지 않는 URL 타입입니다.", + "RegistryName": "레지스트리 이름", + "DescRegistryNameIsEmpty": "레지스트리 이름이 비어 있습니다.", + "RegistryNameAlreadyExists": "레지스트리 이름이 이미 존재합니다. \n레지스트리 이름을 변경해주세요." }, "resourceGroup": { "ResourceGroups": "자원 그룹", diff --git a/resources/i18n/mn.json b/resources/i18n/mn.json index 5790e293ee..3ae1c2bd11 100644 --- a/resources/i18n/mn.json +++ b/resources/i18n/mn.json @@ -1084,7 +1084,10 @@ "ModifyRegistry": "Бүртгэлийг өөрчлөх", "NoRegistryToDisplay": "Харуулах бүртгэл байхгүй", "ConfirmNoUserName": "Хэрэглэгч болон нууц үгийг заагаагүй тул хадгалах уу?", - "DescURLFormat": "Хүчингүй URL төрөл" + "DescURLFormat": "Хүчингүй URL төрөл", + "RegistryName": "Бүртгэлийн нэр", + "DescRegistryNameIsEmpty": "Бүртгэлийн нэр хоосон байна", + "RegistryNameAlreadyExists": "Бүртгэлийн нэр аль хэдийн байна. \nНэмэх бүртгэлийн нэрийг өөрчилнө үү." }, "resourceGroup": { "ResourceGroups": "Нөөцийн бүлгүүд", diff --git a/resources/i18n/ms.json b/resources/i18n/ms.json index 5f8ddfbaa9..db7c19e96a 100644 --- a/resources/i18n/ms.json +++ b/resources/i18n/ms.json @@ -1083,7 +1083,10 @@ "NoRegistryToDisplay": "Tiada Pendaftaran untuk dipaparkan", "ModifyRegistry": "Ubah suai Pendaftaran", "ConfirmNoUserName": "Pengguna dan kata laluan tidak dinyatakan, adakah anda ingin menyimpan?", - "DescURLFormat": "Jenis URL tidak sah" + "DescURLFormat": "Jenis URL tidak sah", + "RegistryName": "Nama Pendaftaran", + "DescRegistryNameIsEmpty": "Nama pendaftaran kosong", + "RegistryNameAlreadyExists": "Nama pendaftaran sudah wujud. \nSila tukar nama pendaftaran untuk ditambahkan." }, "resourceGroup": { "ResourceGroups": "Kumpulan Sumber", diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index 21dd039ebc..68a90dce5d 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Brak rejestrów do wyświetlenia", "ModifyRegistry": "Modyfikacja rejestru", "ConfirmNoUserName": "Użytkownik i hasło nie zostały określone, czy chcesz zapisać?", - "DescURLFormat": "Nieprawidłowy typ adresu URL" + "DescURLFormat": "Nieprawidłowy typ adresu URL", + "RegistryName": "Nazwa rejestru", + "DescRegistryNameIsEmpty": "Nazwa rejestru jest pusta", + "RegistryNameAlreadyExists": "Nazwa rejestru już istnieje. \nZmień nazwę rejestru, aby go dodać." }, "resourceGroup": { "ResourceGroups": "Grupy zasobów", diff --git a/resources/i18n/pt-BR.json b/resources/i18n/pt-BR.json index 031e7955fa..ed9de9d014 100644 --- a/resources/i18n/pt-BR.json +++ b/resources/i18n/pt-BR.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Não há registos a apresentar", "ModifyRegistry": "Modificar o registo", "ConfirmNoUserName": "Utilizador e palavra-passe não especificados, pretende guardar?", - "DescURLFormat": "Tipo de URL inválido" + "DescURLFormat": "Tipo de URL inválido", + "RegistryName": "Nome do registro", + "DescRegistryNameIsEmpty": "O nome do registro está vazio", + "RegistryNameAlreadyExists": "O nome do registro já existe. \nAltere o nome do registro para adicionar." }, "resourceGroup": { "ResourceGroups": "Grupos de Recursos", diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index b513e53701..d2d55bfe57 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Não há registos a apresentar", "ModifyRegistry": "Modificar o registo", "ConfirmNoUserName": "Utilizador e palavra-passe não especificados, pretende guardar?", - "DescURLFormat": "Tipo de URL inválido" + "DescURLFormat": "Tipo de URL inválido", + "RegistryName": "Nome do Registro", + "DescRegistryNameIsEmpty": "O nome do registro está vazio", + "RegistryNameAlreadyExists": "O nome do registro já existe. \nAltere o nome do registro para adicionar." }, "resourceGroup": { "ResourceGroups": "Grupos de Recursos", diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json index b14055dae0..f3e4bb8a8b 100644 --- a/resources/i18n/ru.json +++ b/resources/i18n/ru.json @@ -1082,7 +1082,10 @@ "ModifyRegistry": "Изменение реестра", "NoRegistryToDisplay": "Отсутствие отображаемых реестров", "ConfirmNoUserName": "Пользователь и пароль не указаны, хотите сохранить?", - "DescURLFormat": "Неверный тип URL" + "DescURLFormat": "Неверный тип URL", + "RegistryName": "Имя реестра", + "DescRegistryNameIsEmpty": "Имя реестра пусто", + "RegistryNameAlreadyExists": "Имя реестра уже существует. \nПожалуйста, измените имя реестра для добавления." }, "resourceGroup": { "ResourceGroups": "Группы ресурсов", diff --git a/resources/i18n/th.json b/resources/i18n/th.json index 2943f970a9..6a53e447df 100644 --- a/resources/i18n/th.json +++ b/resources/i18n/th.json @@ -1197,7 +1197,10 @@ "RegistrySuccessfullyModified": "แก้ไขทะเบียนสำเร็จแล้ว", "PleaseSelectOption": "กรุณาเลือกตัวเลือก", "ConfirmNoUserName": "ไม่ได้ระบุชื่อผู้ใช้และรหัสผ่าน คุณต้องการบันทึกหรือไม่?", - "DescURLFormat": "รูปแบบ URL ไม่ถูกต้อง" + "DescURLFormat": "รูปแบบ URL ไม่ถูกต้อง", + "RegistryName": "ชื่อรีจิสทรี", + "DescRegistryNameIsEmpty": "ชื่อรีจิสทรีว่างเปล่า", + "RegistryNameAlreadyExists": "มีชื่อรีจิสทรีอยู่แล้ว \nกรุณาเปลี่ยนชื่อรีจิสทรีที่จะเพิ่ม" }, "resourceGroup": { "ResourceGroups": "กลุ่มทรัพยากร", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index 9e770decc0..369e5c5e82 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Görüntülenecek Kayıt Yok", "ModifyRegistry": "Kayıt Defterini Değiştir", "ConfirmNoUserName": "Kullanıcı ve şifre belirtilmemiş, kaydetmek ister misiniz?", - "DescURLFormat": "Geçersiz URL Türü" + "DescURLFormat": "Geçersiz URL Türü", + "RegistryName": "Kayıt Defteri Adı", + "DescRegistryNameIsEmpty": "Kayıt defteri adı boş", + "RegistryNameAlreadyExists": "Kayıt defteri adı zaten mevcut. \nLütfen eklemek için kayıt defteri adını değiştirin." }, "resourceGroup": { "ResourceGroups": "Kaynak Grupları", diff --git a/resources/i18n/vi.json b/resources/i18n/vi.json index 4fb2180544..a177063d8c 100644 --- a/resources/i18n/vi.json +++ b/resources/i18n/vi.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "Không có đăng ký để hiển thị", "ModifyRegistry": "Sửa đổi sổ đăng ký", "ConfirmNoUserName": "Người dùng và mật khẩu không được chỉ định, bạn có muốn lưu không?", - "DescURLFormat": "Loại URL không hợp lệ" + "DescURLFormat": "Loại URL không hợp lệ", + "RegistryName": "Tên đăng ký", + "DescRegistryNameIsEmpty": "Tên đăng ký trống", + "RegistryNameAlreadyExists": "Tên đăng ký đã tồn tại. \nVui lòng thay đổi tên đăng ký để thêm." }, "resourceGroup": { "ResourceGroups": "Nhóm tài nguyên", diff --git a/resources/i18n/zh-CN.json b/resources/i18n/zh-CN.json index 702f3c63fc..4124ecbc81 100644 --- a/resources/i18n/zh-CN.json +++ b/resources/i18n/zh-CN.json @@ -1084,7 +1084,10 @@ "NoRegistryToDisplay": "无注册表显示", "ModifyRegistry": "修改注册表", "ConfirmNoUserName": "未指定用户和密码,要保存吗?", - "DescURLFormat": "无效的 URL 类型" + "DescURLFormat": "无效的 URL 类型", + "RegistryName": "注册表名称", + "DescRegistryNameIsEmpty": "注册表名称为空", + "RegistryNameAlreadyExists": "注册表名称已存在。\n请更改注册表名称来添加。" }, "resourceGroup": { "ResourceGroups": "资源组", diff --git a/resources/i18n/zh-TW.json b/resources/i18n/zh-TW.json index 192dc173b4..24a007d7e6 100644 --- a/resources/i18n/zh-TW.json +++ b/resources/i18n/zh-TW.json @@ -1083,7 +1083,10 @@ "NoRegistryToDisplay": "无注册表显示", "ModifyRegistry": "修改注册表", "ConfirmNoUserName": "未指定用户和密码,要保存吗?", - "DescURLFormat": "無效的 URL 類型" + "DescURLFormat": "無效的 URL 類型", + "RegistryName": "註冊表名稱", + "DescRegistryNameIsEmpty": "註冊表名稱為空", + "RegistryNameAlreadyExists": "註冊表名稱已存在。\n請更改註冊表名稱來新增。" }, "resourceGroup": { "ResourceGroups": "資源組",