-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
- Name
- Status
- Tag
- Author
- Docker version
- Created
- Pull Command
-
- {{r.name}}
- {{r.status}}
- {{r.tag}}
- {{r.author}}
- {{r.dockerVersion}}
- {{r.created}}
- {{r.pullCommand}}
-
- {{repos.length}} item(s)
-
+
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/repository.component.ts b/src/ui_ng/src/app/repository/repository.component.ts
index b21a0a0f7..02147d4dc 100644
--- a/src/ui_ng/src/app/repository/repository.component.ts
+++ b/src/ui_ng/src/app/repository/repository.component.ts
@@ -1,18 +1,101 @@
-import { Component, OnInit } from '@angular/core';
-import { Repo } from './repo';
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { RepositoryService } from './repository.service';
+import { Repository } from './repository';
+
+import { MessageService } from '../global-message/message.service';
+import { AlertType, DeletionTargets } from '../shared/shared.const';
+
+
+import { DeletionDialogService } from '../shared/deletion-dialog/deletion-dialog.service';
+import { DeletionMessage } from '../shared/deletion-dialog/deletion-message';
+import { Subscription } from 'rxjs/Subscription';
+
+const repositoryTypes = [
+ { key: '0', description: 'REPOSITORY.MY_REPOSITORY' },
+ { key: '1', description: 'REPOSITORY.PUBLIC_REPOSITORY' }
+];
@Component({
selector: 'repository',
templateUrl: 'repository.component.html'
})
export class RepositoryComponent implements OnInit {
- repos: Repo[];
+ changedRepositories: Repository[];
+
+ projectId: number;
+ repositoryTypes = repositoryTypes;
+ currentRepositoryType: {};
+ lastFilteredRepoName: string;
+
+ subscription: Subscription;
+
+ constructor(
+ private route: ActivatedRoute,
+ private repositoryService: RepositoryService,
+ private messageService: MessageService,
+ private deletionDialogService: DeletionDialogService
+ ) {
+ this.subscription = this.deletionDialogService
+ .deletionConfirm$
+ .subscribe(
+ message=>{
+ let repoName = message.data;
+ this.repositoryService
+ .deleteRepository(repoName)
+ .subscribe(
+ response=>{
+ this.refresh();
+ console.log('Successful deleted repo:' + repoName);
+ },
+ error=>this.messageService.announceMessage(error.status, 'Failed to delete repo:' + repoName, AlertType.DANGER)
+ );
+ }
+ );
+ }
+
ngOnInit(): void {
- this.repos = [
- { name: 'ubuntu', status: 'ready', tag: '14.04', author: 'Admin', dockerVersion: '1.10.1', created: '2016-10-10', pullCommand: 'docker pull 10.117.5.61/project01/ubuntu:14.04' },
- { name: 'mysql', status: 'ready', tag: '5.6', author: 'docker', dockerVersion: '1.11.2', created: '2016-09-23', pullCommand: 'docker pull 10.117.5.61/project01/mysql:5.6' },
- { name: 'photon', status: 'ready', tag: 'latest', author: 'Admin', dockerVersion: '1.10.1', created: '2016-11-10', pullCommand: 'docker pull 10.117.5.61/project01/photon:latest' },
- ];
+ this.projectId = this.route.snapshot.parent.params['id'];
+ this.currentRepositoryType = this.repositoryTypes[0];
+ this.lastFilteredRepoName = '';
+ this.retrieve(this.lastFilteredRepoName);
+ }
+
+ ngOnDestroy(): void {
+ if(this.subscription) {
+ this.subscription.unsubscribe();
+ }
+ }
+
+ retrieve(repoName: string) {
+ this.repositoryService
+ .listRepositories(this.projectId, repoName)
+ .subscribe(
+ response=>this.changedRepositories=response,
+ error=>this.messageService.announceMessage(error.status, 'Failed to list repositories.', AlertType.DANGER)
+ );
+ }
+
+ doFilterRepositoryByType(type: string) {
+ this.currentRepositoryType = this.repositoryTypes.find(r=>r.key == type);
+ }
+
+ doSearchRepoNames(repoName: string) {
+ this.lastFilteredRepoName = repoName;
+ this.retrieve(this.lastFilteredRepoName);
+
+ }
+
+ deleteRepo(repoName: string) {
+ let message = new DeletionMessage(
+ 'REPOSITORY.DELETION_TITLE_REPO',
+ 'REPOSITORY.DELETION_SUMMARY_REPO',
+ repoName, repoName, DeletionTargets.REPOSITORY);
+ this.deletionDialogService.openComfirmDialog(message);
+ }
+
+ refresh() {
+ this.retrieve('');
}
}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/repository.module.ts b/src/ui_ng/src/app/repository/repository.module.ts
index 446149a9a..c6d257fff 100644
--- a/src/ui_ng/src/app/repository/repository.module.ts
+++ b/src/ui_ng/src/app/repository/repository.module.ts
@@ -1,10 +1,25 @@
import { NgModule } from '@angular/core';
-import { RepositoryComponent } from './repository.component';
+import { RouterModule } from '@angular/router';
+
import { SharedModule } from '../shared/shared.module';
+import { RepositoryComponent } from './repository.component';
+import { ListRepositoryComponent } from './list-repository/list-repository.component';
+import { TagRepositoryComponent } from './tag-repository/tag-repository.component';
+
+import { RepositoryService } from './repository.service';
+
@NgModule({
- imports: [ SharedModule ],
- declarations: [ RepositoryComponent ],
- exports: [ RepositoryComponent ]
+ imports: [
+ SharedModule,
+ RouterModule
+ ],
+ declarations: [
+ RepositoryComponent,
+ ListRepositoryComponent,
+ TagRepositoryComponent
+ ],
+ exports: [ RepositoryComponent ],
+ providers: [ RepositoryService ]
})
export class RepositoryModule {}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/repository.service.ts b/src/ui_ng/src/app/repository/repository.service.ts
new file mode 100644
index 000000000..7af17dd07
--- /dev/null
+++ b/src/ui_ng/src/app/repository/repository.service.ts
@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+import { Http } from '@angular/http';
+
+import { Repository } from './repository';
+import { Observable } from 'rxjs/Observable'
+
+@Injectable()
+export class RepositoryService {
+
+ constructor(private http: Http){}
+
+ listRepositories(projectId: number, repoName: string): Observable
{
+ console.log('List repositories with project ID:' + projectId);
+ return this.http
+ .get(`/api/repositories?project_id=${projectId}&q=${repoName}&detail=1`)
+ .map(response=>response.json() as Repository[])
+ .catch(error=>Observable.throw(error));
+ }
+
+ deleteRepository(repoName: string): Observable {
+ console.log('Delete repository with repo name:' + repoName);
+ return this.http
+ .delete(`/api/repositories?repo_name=${repoName}`)
+ .map(response=>response.status)
+ .catch(error=>Observable.throw(error));
+ }
+}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/repository.ts b/src/ui_ng/src/app/repository/repository.ts
index bc43a81ed..13199894f 100644
--- a/src/ui_ng/src/app/repository/repository.ts
+++ b/src/ui_ng/src/app/repository/repository.ts
@@ -1,5 +1,32 @@
+/*
+ {
+ "id": "2",
+ "name": "library/mysql",
+ "owner_id": 1,
+ "project_id": 1,
+ "description": "",
+ "pull_count": 0,
+ "star_count": 0,
+ "tags_count": 1,
+ "creation_time": "2017-02-14T09:22:58Z",
+ "update_time": "0001-01-01T00:00:00Z"
+ }
+*/
+
export class Repository {
- name:string;
- version:string;
- count:number;
+ id: number;
+ name: string;
+ owner_id: number;
+ project_id: number;
+ description: string;
+ pull_count: number;
+ start_count: number;
+ tags_count: number;
+ creation_time: Date;
+ update_time: Date;
+
+ constructor(name: string, tags_count: number) {
+ this.name = name;
+ this.tags_count = tags_count;
+ }
}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.html b/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.html
new file mode 100644
index 000000000..0fa603c02
--- /dev/null
+++ b/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.html
@@ -0,0 +1,24 @@
+< {{'REPOSITORY.REPOSITORIES' | translate}}
+{{repoName}} {{tags ? tags.length : 0}}
+
+ {{'REPOSITORY.TAG' | translate}}
+ {{'REPOSITORY.PULL_COMMAND' | translate}}
+ {{'REPOSITORY.VERIFIED' | translate}}
+ {{'REPOSITORY.AUTHOR' | translate}}
+ {{'REPOSITORY.CREATED' | translate}}
+ {{'REPOSITORY.DOCKER_VERSION' | translate}}
+ {{'REPOSITORY.ARCHITECTURE' | translate}}
+ {{'REPOSITORY.OS' | translate}}
+
+
+
+
+
+ {{'REPOSITORY.SHOW_DETAILS'}}
+
+ {{'REPOSITORY.DELETE' | translate}}
+
+
+
+ {{tags ? tags.length : 0}} {{'REPOSITORY.ITEMS' | translate}}
+
\ No newline at end of file
diff --git a/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.ts b/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.ts
new file mode 100644
index 000000000..b8713e48b
--- /dev/null
+++ b/src/ui_ng/src/app/repository/tag-repository/tag-repository.component.ts
@@ -0,0 +1,24 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+
+@Component({
+ selector: 'tag-repository',
+ templateUrl: 'tag-repository.component.html'
+})
+export class TagRepositoryComponent implements OnInit {
+
+ projectId: number;
+ repoName: string;
+
+ constructor(private route: ActivatedRoute) {}
+
+ ngOnInit() {
+ this.projectId = this.route.snapshot.params['id'];
+ this.repoName = this.route.snapshot.params['repo'];
+ }
+
+ deleteTag(tagName: string) {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/shared/create-edit-policy/create-edit-policy.component.html b/src/ui_ng/src/app/shared/create-edit-policy/create-edit-policy.component.html
index 08dad367f..db9943edd 100644
--- a/src/ui_ng/src/app/shared/create-edit-policy/create-edit-policy.component.html
+++ b/src/ui_ng/src/app/shared/create-edit-policy/create-edit-policy.component.html
@@ -1,5 +1,5 @@
- New Replication Rule
+ {{modalTitle}}
-
+
-
+
\ No newline at end of file
diff --git a/src/ui_ng/src/app/shared/list-policy/list-policy.component.html b/src/ui_ng/src/app/shared/list-policy/list-policy.component.html
index 4636de768..6a1935240 100644
--- a/src/ui_ng/src/app/shared/list-policy/list-policy.component.html
+++ b/src/ui_ng/src/app/shared/list-policy/list-policy.component.html
@@ -1,10 +1,10 @@
- Name
- Project
- Description
- Destination
- Last Start Time
- Activation
+ {{'REPLICATION.NAME' | translate}}
+ {{'REPLICATION.PROJECT' | translate}}
+ {{'REPLICATION.DESCRIPTION' | translate}}
+ {{'REPLICATION.DESTINATION_NAME' | translate}}
+ {{'REPLICATION.LAST_START_TIME' | translate}}
+ {{'REPLICATION.ACTIVATION' | translate}}
{{p.name}}
{{p.project_name}}
@@ -12,13 +12,13 @@
{{p.target_name}}
{{p.start_time}}
- {{p.enabled === 1 ? 'Enabled' : 'Disabled'}}
+ {{ (p.enabled === 1 ? 'REPLICATION.ENABLED' : 'REPLICATION.DISABLED') | translate}}
- Edit Policy
- {{ p.enabled === 0 ? 'Enable' : 'Disabled' }}
- Delete
+ {{'REPLICATION.EDIT_POLICY' | translate}}
+ {{ (p.enabled === 0 ? 'REPLICATION.ENABLE' : 'REPLICATION.DISABLE') | translate}}
+ {{'REPLICATION.DELETE_POLICY' | translate}}
- {{ (policies ? policies.length : 0) }} item(s)
+ {{ (policies ? policies.length : 0) }} {{'REPLICATION.ITEMS' | translate}}
\ No newline at end of file
diff --git a/src/ui_ng/src/app/shared/shared.const.ts b/src/ui_ng/src/app/shared/shared.const.ts
index d7bd16a78..cfb3ba673 100644
--- a/src/ui_ng/src/app/shared/shared.const.ts
+++ b/src/ui_ng/src/app/shared/shared.const.ts
@@ -14,7 +14,7 @@ export const httpStatusCode = {
"Forbidden": 403
};
export const enum DeletionTargets {
- EMPTY, PROJECT, PROJECT_MEMBER, USER, POLICY, TARGET
+ EMPTY, PROJECT, PROJECT_MEMBER, USER, POLICY, TARGET, REPOSITORY
};
export const harborRootRoute = "/harbor";
diff --git a/src/ui_ng/src/ng/i18n/lang/en-lang.json b/src/ui_ng/src/ng/i18n/lang/en-lang.json
index 2afc28c22..a8164ba62 100644
--- a/src/ui_ng/src/ng/i18n/lang/en-lang.json
+++ b/src/ui_ng/src/ng/i18n/lang/en-lang.json
@@ -7,13 +7,13 @@
"TITLE": "Sign Up"
},
"BUTTON": {
- "CANCEL": "Cancel",
- "OK": "Ok",
+ "CANCEL": "CANCEL",
+ "OK": "OK",
"DELETE": "DELETE",
"LOG_IN": "LOG IN",
"SIGN_UP_LINK": "Sign up for an account",
"SIGN_UP": "SIGN UP",
- "CONFIRM": "Confirm",
+ "CONFIRM": "CONFIRM",
"SEND": "SEND",
"SAVE": "SAVE",
"TEST_MAIL": "TEST MAIL SERVER",
@@ -113,6 +113,8 @@
"MY_PROJECTS": "My Projects",
"PUBLIC_PROJECTS": "Public Projects",
"NEW_PROJECT": "New Project",
+ "NAME_IS_REQUIRED": "Project name is required.",
+ "NAME_MINIMUM_LENGTH": "Project name is too short, it should be greater than 2 characters.",
"NAME_ALREADY_EXISTS": "Project name already exists.",
"NAME_IS_ILLEGAL": "Project name is illegal.",
"UNKNOWN_ERROR": "Unknown error occurred while creating project.",
@@ -125,7 +127,8 @@
"REPOSITORIES": "Repositories",
"REPLICATION": "Replication",
"USERS": "Users",
- "LOGS": "Logs"
+ "LOGS": "Logs",
+ "PROJECTS": "Projects"
},
"MEMBER": {
"NEW_MEMBER": "New Member",
@@ -162,13 +165,105 @@
"FILTER_PLACEHOLDER": "Filter Logs"
},
"REPLICATION": {
+ "REPLICATION_RULES": "Replication Rules",
+ "ENDPOINTS": "Endpoints",
"FILTER_POLICIES_PLACEHOLDER": "Filter Policies",
"FILTER_JOBS_PLACEHOLDER": "Filter Jobs",
"DELETION_TITLE": "Confirm Policy Deletion",
"DELETION_SUMMARY": "Do you want to delete policy {{param}}?",
"FILTER_TARGETS_PLACEHOLDER": "Filter Targets",
"DELETION_TITLE_TARGET": "Confirm Target Deletion",
- "DELETION_SUMMARY_TARGET": "Do you want to delete target {{param}}?"
+ "DELETION_SUMMARY_TARGET": "Do you want to delete target {{param}}?",
+ "ADD_POLICY": "Add Policy",
+ "EDIT_POLICY": "Edit Policy",
+ "DELETE_POLICY": "Delete Policy",
+ "TEST_CONNECTION": "Test Connection",
+ "TESTING_CONNECTION": "Testing Connection...",
+ "TEST_CONNECTION_SUCCESS": "Connection tested successfully.",
+ "TEST_CONNECTION_FAILURE": "Failed to ping target.",
+ "NAME": "Name",
+ "PROJECT": "Project",
+ "NAME_IS_REQUIRED": "Name is required.",
+ "DESCRIPTION": "Description",
+ "ENABLE": "Enable",
+ "DISABLE": "Disable",
+ "DESTINATION_NAME": "Destination Name",
+ "DESTINATION_NAME_IS_REQUIRED": "Destination name is required.",
+ "NEW_DESTINATION": "New Destination",
+ "DESTINATION_URL": "Endpoint URL",
+ "DESTINATION_URL_IS_REQUIRED": "Endpoint URL is required.",
+ "DESTINATION_USERNAME": "Username",
+ "DESTINATION_PASSWORD": "Password",
+ "REPLICATION_RULE": "Replication Rule",
+ "ALL_STATUS": "All Status",
+ "ENABLED": "Enabled",
+ "DISABLED": "Disabled",
+ "LAST_START_TIME": "Last Start Time",
+ "ACTIVATION": "Activation",
+ "REPLICATION_JOBS": "Replication Jobs",
+ "ALL": "All",
+ "PENDING": "Pending",
+ "RUNNING": "Running",
+ "ERROR": "Error",
+ "RETRYING": "Retrying",
+ "STOPPED": "Stopped",
+ "FINISHED": "Finished",
+ "CANCELED": "Canceled",
+ "SIMPLE": "Simple",
+ "ADVANCED": "Advanced",
+ "STATUS": "Status",
+ "OPERATION": "Operation",
+ "CREATION_TIME": "Start Time",
+ "END_TIME": "End Time",
+ "LOGS": "Logs",
+ "ITEMS": "item(s)"
+ },
+ "DESTINATION": {
+ "ENDPOINT": "Endpoint",
+ "NAME": "Destination Name",
+ "NAME_IS_REQUIRED": "Destination name is required.",
+ "URL": "Endpoint URL",
+ "URL_IS_REQUIRED": "Endpoint URL is required.",
+ "USERNAME": "Username",
+ "PASSWORD": "Password",
+ "TEST_CONNECTION": "Test Connection",
+ "TITLE_EDIT": "Edit Endpoint",
+ "TITLE_ADD": "Create Endpoint",
+ "DELETE": "Delete Endpoint",
+ "TESTING_CONNECTION": "Testing Connection...",
+ "TEST_CONNECTION_SUCCESS": "Connection tested successfully.",
+ "TEST_CONNECTION_FAILURE": "Failed to ping target.",
+ "CONFLICT_NAME": "Name or endpoint URL already exists.",
+ "INVALID_NAME": "Invalid destination name.",
+ "FAILED_TO_GET_TARGET": "Failed to get endpoint.",
+ "CREATION_TIME": "Creation Time",
+ "ITEMS": "item(s)"
+ },
+ "REPOSITORY": {
+ "COPY_ID": "Copy ID",
+ "COPY_PARENT_ID": "Copy Parent ID",
+ "DELETE": "Delete",
+ "NAME": "Name",
+ "TAGS_COUNT": "Tags",
+ "PULL_COUNT": "Pulls",
+ "PULL_COMMAND": "Pull Command",
+ "MY_REPOSITORY": "My Repository",
+ "PUBLIC_REPOSITORY": "Public Repository",
+ "DELETION_TITLE_REPO": "Confirm Repository Deletion",
+ "DELETION_SUMMARY_REPO": "Do you want to delete repository {{param}}?",
+ "DELETION_TITLE_TAG": "Confirm Tag Deletion",
+ "DELETION_SUMMARY_TAG": "Do you want to delete tag {{param}}?",
+ "FILTER_FOR_REPOSITORIES": "Filter for repositories",
+ "TAG": "Tag",
+ "VERIFIED": "Verified",
+ "AUTHOR": "Author",
+ "CREATED": "Creation Time",
+ "DOCKER_VERSION": "Docker Version",
+ "ARCHITECTURE": "Architecture",
+ "OS": "OS",
+ "SHOW_DETAILS": "Show Details",
+ "REPOSITORIES": "Repositories",
+ "ITEMS": "item(s)"
},
"ALERT": {
"FORM_CHANGE_CONFIRMATION": "Form value changed, confirm to cancel?"
diff --git a/src/ui_ng/src/ng/i18n/lang/zh-lang.json b/src/ui_ng/src/ng/i18n/lang/zh-lang.json
index 3081e6870..dae486713 100644
--- a/src/ui_ng/src/ng/i18n/lang/zh-lang.json
+++ b/src/ui_ng/src/ng/i18n/lang/zh-lang.json
@@ -113,6 +113,8 @@
"MY_PROJECTS": "我的项目",
"PUBLIC_PROJECTS": "公开项目",
"NEW_PROJECT": "新建项目",
+ "NAME_IS_REQUIRED": "项目名称为必填项",
+ "NAME_MINIMUM_LENGTH": "项目名称长度过短,至少多于2个字符。",
"NAME_ALREADY_EXISTS": "项目名称已存在。",
"NAME_IS_ILLEGAL": "项目名称非法。",
"UNKNOWN_ERROR": "创建项目时发生未知错误。",
@@ -125,7 +127,8 @@
"REPOSITORIES": "镜像仓库",
"REPLICATION": "复制",
"USERS": "用户",
- "LOGS": "日志"
+ "LOGS": "日志",
+ "PROJECTS": "项目"
},
"MEMBER": {
"NEW_MEMBER": "新增成员",
@@ -163,14 +166,105 @@
"FILTER_PLACEHOLDER": "过滤日志"
},
"REPLICATION": {
+ "REPLICATION_RULES": "复制",
+ "ENDPOINTS": "目标",
"FILTER_POLICIES_PLACEHOLDER": "过滤策略",
"FILTER_JOBS_PLACEHOLDER": "过滤任务",
"DELETION_TITLE": "删除策略确认",
"DELETION_SUMMARY": "确认删除策略 {{param}}?",
"FILTER_TARGETS_PLACEHOLDER": "过滤目标",
"DELETION_TITLE_TARGET": "删除目标确认",
- "DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?"
-
+ "DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?",
+ "ADD_POLICY": "新增策略",
+ "EDIT_POLICY": "修改策略",
+ "DELETE_POLICY": "删除策略",
+ "TEST_CONNECTION": "测试连接",
+ "TESTING_CONNECTION": "正在测试连接...",
+ "TEST_CONNECTION_SUCCESS": "测试连接成功。",
+ "TEST_CONNECTION_FAILURE": "测试连接失败。",
+ "NAME": "名称",
+ "PROJECT": "项目",
+ "NAME_IS_REQUIRED": "名称为必填项",
+ "DESCRIPTION": "描述",
+ "ENABLE": "启用",
+ "DISABLE": "停用",
+ "DESTINATION_NAME": "目标名",
+ "DESTINATION_NAME_IS_REQUIRED": "目标名称为必填项。",
+ "NEW_DESTINATION": "创建目标",
+ "DESTINATION_URL": "目标URL",
+ "DESTINATION_URL_IS_REQUIRED": "目标URL为必填项。",
+ "DESTINATION_USERNAME": "用户名",
+ "DESTINATION_PASSWORD": "密码",
+ "REPLICATION_RULE": "创建策略",
+ "ALL_STATUS": "所有状态",
+ "ENABLED": "启用",
+ "DISABLED": "停用",
+ "LAST_START_TIME": "上次起始时间",
+ "ACTIVATION": "活动状态",
+ "REPLICATION_JOBS": "复制任务",
+ "ALL": "全部",
+ "PENDING": "挂起",
+ "RUNNING": "运行中",
+ "ERROR": "错误",
+ "RETRYING": "重试中",
+ "STOPPED": "已停止",
+ "FINISHED": "已完成",
+ "CANCELED": "已取消",
+ "SIMPLE": "简单检索",
+ "ADVANCED": "高级检索",
+ "STATUS": "状态",
+ "OPERATION": "操作",
+ "CREATION_TIME": "创建时间",
+ "END_TIME": "结束时间",
+ "LOGS": "日志",
+ "ITEMS": "条记录"
+ },
+ "DESTINATION": {
+ "ENDPOINT": "目标",
+ "NAME": "目标名",
+ "NAME_IS_REQUIRED": "目标名为必填项。",
+ "URL": "目标URL",
+ "URL_IS_REQUIRED": "目标URL为必填项。",
+ "USERNAME": "用户名",
+ "PASSWORD": "密码",
+ "TEST_CONNECTION": "测试连接",
+ "TITLE_EDIT": "编辑目标",
+ "TITLE_ADD": "新建目标",
+ "DELETE": "删除目标",
+ "TESTING_CONNECTION": "正在测试连接...",
+ "TEST_CONNECTION_SUCCESS": "测试连接成功。",
+ "TEST_CONNECTION_FAILURE": "测试连接失败。",
+ "CONFLICT_NAME": "目标名或目标URL已存在。",
+ "INVALID_NAME": "无效的目标名称。",
+ "FAILED_TO_GET_TARGET": "获取目标失败。",
+ "CREATION_TIME": "创建时间",
+ "ITEMS": "条记录"
+ },
+ "REPOSITORY": {
+ "COPY_ID": "复制ID",
+ "COPY_PARENT_ID": "复制父级ID",
+ "DELETE": "删除",
+ "NAME": "名称",
+ "TAGS_COUNT": "标签数",
+ "PULL_COUNT": "下载数",
+ "PULL_COMMAND": "Pull命令",
+ "MY_REPOSITORY": "我的镜像",
+ "PUBLIC_REPOSITORY": "公共镜像",
+ "DELETION_TITLE_REPO": "删除镜像仓库确认",
+ "DELETION_SUMMARY_REPO": "确认删除镜像仓库 {{param}}?",
+ "DELETION_TITLE_TAG": "删除镜像标签确认",
+ "DELETION_SUMMARY_TAG": "确认删除镜像标签 {{param}}?",
+ "FILTER_FOR_REPOSITORIES": "过滤镜像仓库",
+ "TAG": "标签",
+ "VERIFIED": "已验证",
+ "AUTHOR": "作者",
+ "CREATED": "创建时间",
+ "DOCKER_VERSION": "Docker版本",
+ "ARCHITECTURE": "架构",
+ "OS": "操作系统",
+ "SHOW_DETAILS": "显示详细",
+ "REPOSITORIES": "镜像仓库",
+ "ITEMS": "条记录"
},
"ALERT": {
"FORM_CHANGE_CONFIRMATION": "表单内容改变,确认取消?"