mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-17 04:11:24 +01:00
Merge branch 'master' into fix_issue_#2793
This commit is contained in:
commit
5c876621ec
@ -37,4 +37,5 @@ GODEBUG=netdns=cgo
|
|||||||
ADMIRAL_URL=$admiral_url
|
ADMIRAL_URL=$admiral_url
|
||||||
WITH_NOTARY=$with_notary
|
WITH_NOTARY=$with_notary
|
||||||
WITH_CLAIR=$with_clair
|
WITH_CLAIR=$with_clair
|
||||||
|
CLAIR_DB_PASSWORD=$pg_password
|
||||||
RESET=false
|
RESET=false
|
||||||
|
@ -30,6 +30,10 @@ secretkey_path = /data
|
|||||||
#Admiral's url, comment this attribute, or set its value to NA when Harbor is standalone
|
#Admiral's url, comment this attribute, or set its value to NA when Harbor is standalone
|
||||||
admiral_url = NA
|
admiral_url = NA
|
||||||
|
|
||||||
|
#The password of the Clair's postgres database, only effective when Harbor is deployed with Clair.
|
||||||
|
#Please update it before deployment, subsequent update will cause Clair's API server and Harbor unable to access Clair's database.
|
||||||
|
clair_db_password = password
|
||||||
|
|
||||||
#NOTES: The properties between BEGIN INITIAL PROPERTIES and END INITIAL PROPERTIES
|
#NOTES: The properties between BEGIN INITIAL PROPERTIES and END INITIAL PROPERTIES
|
||||||
#only take effect in the first boot, the subsequent changes of these properties
|
#only take effect in the first boot, the subsequent changes of these properties
|
||||||
#should be performed on web ui
|
#should be performed on web ui
|
||||||
|
10
make/prepare
10
make/prepare
@ -153,6 +153,7 @@ if rcp.has_option("configuration", "admiral_url"):
|
|||||||
admiral_url = rcp.get("configuration", "admiral_url")
|
admiral_url = rcp.get("configuration", "admiral_url")
|
||||||
else:
|
else:
|
||||||
admiral_url = ""
|
admiral_url = ""
|
||||||
|
pg_password = rcp.get("configuration", "clair_db_password")
|
||||||
secret_key = get_secret_key(secretkey_path)
|
secret_key = get_secret_key(secretkey_path)
|
||||||
########
|
########
|
||||||
|
|
||||||
@ -225,13 +226,15 @@ render(os.path.join(templates_dir, "adminserver", "env"),
|
|||||||
token_expiration=token_expiration,
|
token_expiration=token_expiration,
|
||||||
admiral_url=admiral_url,
|
admiral_url=admiral_url,
|
||||||
with_notary=args.notary_mode,
|
with_notary=args.notary_mode,
|
||||||
with_clair=args.clair_mode
|
with_clair=args.clair_mode,
|
||||||
|
pg_password=pg_password
|
||||||
)
|
)
|
||||||
|
|
||||||
render(os.path.join(templates_dir, "ui", "env"),
|
render(os.path.join(templates_dir, "ui", "env"),
|
||||||
ui_conf_env,
|
ui_conf_env,
|
||||||
ui_secret=ui_secret,
|
ui_secret=ui_secret,
|
||||||
jobservice_secret=jobservice_secret,)
|
jobservice_secret=jobservice_secret,
|
||||||
|
)
|
||||||
|
|
||||||
render(os.path.join(templates_dir, "registry",
|
render(os.path.join(templates_dir, "registry",
|
||||||
"config.yml"),
|
"config.yml"),
|
||||||
@ -370,11 +373,10 @@ if args.notary_mode:
|
|||||||
render(os.path.join(notary_temp_dir, "signer_env"), os.path.join(notary_config_dir, "signer_env"), alias = default_alias)
|
render(os.path.join(notary_temp_dir, "signer_env"), os.path.join(notary_config_dir, "signer_env"), alias = default_alias)
|
||||||
|
|
||||||
if args.clair_mode:
|
if args.clair_mode:
|
||||||
pg_password = "password"
|
|
||||||
clair_temp_dir = os.path.join(templates_dir, "clair")
|
clair_temp_dir = os.path.join(templates_dir, "clair")
|
||||||
clair_config_dir = prep_conf_dir(config_dir, "clair")
|
clair_config_dir = prep_conf_dir(config_dir, "clair")
|
||||||
print("Copying offline data file for clair DB")
|
|
||||||
if os.path.exists(os.path.join(clair_config_dir, "postgresql-init.d")):
|
if os.path.exists(os.path.join(clair_config_dir, "postgresql-init.d")):
|
||||||
|
print("Copying offline data file for clair DB")
|
||||||
shutil.rmtree(os.path.join(clair_config_dir, "postgresql-init.d"))
|
shutil.rmtree(os.path.join(clair_config_dir, "postgresql-init.d"))
|
||||||
shutil.copytree(os.path.join(clair_temp_dir, "postgresql-init.d"), os.path.join(clair_config_dir, "postgresql-init.d"))
|
shutil.copytree(os.path.join(clair_temp_dir, "postgresql-init.d"), os.path.join(clair_config_dir, "postgresql-init.d"))
|
||||||
postgres_env = os.path.join(clair_config_dir, "postgres_env")
|
postgres_env = os.path.join(clair_config_dir, "postgres_env")
|
||||||
|
@ -45,6 +45,7 @@ var (
|
|||||||
common.LDAPSearchPwd,
|
common.LDAPSearchPwd,
|
||||||
common.MySQLPassword,
|
common.MySQLPassword,
|
||||||
common.AdminInitialPassword,
|
common.AdminInitialPassword,
|
||||||
|
common.ClairDBPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
// all configurations need read from environment variables
|
// all configurations need read from environment variables
|
||||||
@ -120,6 +121,7 @@ var (
|
|||||||
env: "WITH_CLAIR",
|
env: "WITH_CLAIR",
|
||||||
parse: parseStringToBool,
|
parse: parseStringToBool,
|
||||||
},
|
},
|
||||||
|
common.ClairDBPassword: "CLAIR_DB_PASSWORD",
|
||||||
}
|
}
|
||||||
|
|
||||||
// configurations need read from environment variables
|
// configurations need read from environment variables
|
||||||
@ -144,6 +146,7 @@ var (
|
|||||||
env: "WITH_CLAIR",
|
env: "WITH_CLAIR",
|
||||||
parse: parseStringToBool,
|
parse: parseStringToBool,
|
||||||
},
|
},
|
||||||
|
common.ClairDBPassword: "CLAIR_DB_PASSWORD",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ const (
|
|||||||
WithNotary = "with_notary"
|
WithNotary = "with_notary"
|
||||||
WithClair = "with_clair"
|
WithClair = "with_clair"
|
||||||
ScanAllPolicy = "scan_all_policy"
|
ScanAllPolicy = "scan_all_policy"
|
||||||
|
ClairDBPassword = "clair_db_password"
|
||||||
|
|
||||||
DefaultClairEndpoint = "http://clair:6060"
|
DefaultClairEndpoint = "http://clair:6060"
|
||||||
)
|
)
|
||||||
|
@ -43,13 +43,13 @@ type Database interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InitClairDB ...
|
// InitClairDB ...
|
||||||
func InitClairDB() error {
|
func InitClairDB(password string) error {
|
||||||
//TODO: Read from env vars.
|
//Except for password other information will not be configurable, so keep it hard coded for 1.2.0.
|
||||||
p := &pgsql{
|
p := &pgsql{
|
||||||
host: "postgres",
|
host: "postgres",
|
||||||
port: 5432,
|
port: 5432,
|
||||||
usr: "postgres",
|
usr: "postgres",
|
||||||
pwd: "password",
|
pwd: password,
|
||||||
database: "postgres",
|
database: "postgres",
|
||||||
sslmode: false,
|
sslmode: false,
|
||||||
}
|
}
|
||||||
|
@ -170,23 +170,23 @@ func get(client *http.Client, url, token string, username ...string) (*AuthConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login with credential and returns auth context and error
|
// Login with credential and returns auth context and error
|
||||||
func Login(client *http.Client, url, username, password string) (*AuthContext, error) {
|
func Login(client *http.Client, url, username, password, token string) (*AuthContext, error) {
|
||||||
data, err := json.Marshal(&struct {
|
data, err := json.Marshal(&struct {
|
||||||
Username string `json:"username"`
|
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}{
|
}{
|
||||||
Username: username,
|
|
||||||
Password: password,
|
Password: password,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodPost, buildLoginURL(url), bytes.NewBuffer(data))
|
req, err := http.NewRequest(http.MethodPost, buildLoginURL(url, username), bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.Header.Add(AuthTokenHeader, token)
|
||||||
|
|
||||||
return send(client, req)
|
return send(client, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ func buildSpecificUserAuthCtxURL(url, principalID string) string {
|
|||||||
strings.TrimRight(url, "/"), principalID)
|
strings.TrimRight(url, "/"), principalID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO update the url
|
func buildLoginURL(url, principalID string) string {
|
||||||
func buildLoginURL(url string) string {
|
return fmt.Sprintf("%s/auth/idm/principals/%s/security-context",
|
||||||
return strings.TrimRight(url, "/") + "/sso/login"
|
strings.TrimRight(url, "/"), principalID)
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ var (
|
|||||||
// AdmiralClient is initialized only under integration deploy mode
|
// AdmiralClient is initialized only under integration deploy mode
|
||||||
// and can be passed to project manager as a parameter
|
// and can be passed to project manager as a parameter
|
||||||
AdmiralClient *http.Client
|
AdmiralClient *http.Client
|
||||||
|
// TokenReader is used in integration mode to read token
|
||||||
|
TokenReader pms.TokenReader
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init configurations
|
// Init configurations
|
||||||
@ -126,10 +128,11 @@ func initProjectManager() {
|
|||||||
path = defaultTokenFilePath
|
path = defaultTokenFilePath
|
||||||
}
|
}
|
||||||
log.Infof("service token file path: %s", path)
|
log.Infof("service token file path: %s", path)
|
||||||
|
TokenReader = &pms.FileTokenReader{
|
||||||
|
Path: path,
|
||||||
|
}
|
||||||
GlobalProjectMgr = pms.NewProjectManager(AdmiralClient,
|
GlobalProjectMgr = pms.NewProjectManager(AdmiralClient,
|
||||||
AdmiralEndpoint(), &pms.FileTokenReader{
|
AdmiralEndpoint(), TokenReader)
|
||||||
Path: path,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load configurations
|
// Load configurations
|
||||||
@ -358,12 +361,20 @@ func ClairEndpoint() string {
|
|||||||
return common.DefaultClairEndpoint
|
return common.DefaultClairEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClairDBPassword returns the password for accessing Clair's DB.
|
||||||
|
func ClairDBPassword() (string, error) {
|
||||||
|
cfg, err := mg.Get()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return cfg[common.ClairDBPassword].(string), nil
|
||||||
|
}
|
||||||
|
|
||||||
// AdmiralEndpoint returns the URL of admiral, if Harbor is not deployed with admiral it should return an empty string.
|
// AdmiralEndpoint returns the URL of admiral, if Harbor is not deployed with admiral it should return an empty string.
|
||||||
func AdmiralEndpoint() string {
|
func AdmiralEndpoint() string {
|
||||||
cfg, err := mg.Get()
|
cfg, err := mg.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to get configuration, will return empty string as admiral's endpoint, error: %v", err)
|
log.Errorf("Failed to get configuration, will return empty string as admiral's endpoint, error: %v", err)
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if e, ok := cfg[common.AdmiralEndpoint].(string); !ok || e == "NA" {
|
if e, ok := cfg[common.AdmiralEndpoint].(string); !ok || e == "NA" {
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
beegoctx "github.com/astaxie/beego/context"
|
beegoctx "github.com/astaxie/beego/context"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
@ -133,8 +134,13 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token, err := config.TokenReader.ReadToken()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to read solution user token: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
authCtx, err := authcontext.Login(config.AdmiralClient,
|
authCtx, err := authcontext.Login(config.AdmiralClient,
|
||||||
config.AdmiralEndpoint(), username, password)
|
config.AdmiralEndpoint(), username, password, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to authenticate %s: %v", username, err)
|
log.Errorf("failed to authenticate %s: %v", username, err)
|
||||||
return false
|
return false
|
||||||
@ -172,7 +178,7 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func filterReq(req *http.Request) bool {
|
func filterReq(req *http.Request) bool {
|
||||||
path := req.URL.Path
|
path := strings.TrimRight(req.URL.Path, "/")
|
||||||
if path == "/api/projects" && req.Method == http.MethodPost ||
|
if path == "/api/projects" && req.Method == http.MethodPost ||
|
||||||
path == "/service/token" && req.Method == http.MethodGet {
|
path == "/service/token" && req.Method == http.MethodGet {
|
||||||
return true
|
return true
|
||||||
|
@ -92,7 +92,11 @@ func main() {
|
|||||||
log.Fatalf("failed to initialize database: %v", err)
|
log.Fatalf("failed to initialize database: %v", err)
|
||||||
}
|
}
|
||||||
if config.WithClair() {
|
if config.WithClair() {
|
||||||
if err := dao.InitClairDB(); err != nil {
|
clairDBPassword, err := config.ClairDBPassword()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to load clair database information: %v", err)
|
||||||
|
}
|
||||||
|
if err := dao.InitClairDB(clairDBPassword); err != nil {
|
||||||
log.Fatalf("failed to initialize clair database: %v", err)
|
log.Fatalf("failed to initialize clair database: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/vmware/harbor/src/common/dao"
|
"github.com/vmware/harbor/src/common/dao"
|
||||||
|
clairdao "github.com/vmware/harbor/src/common/dao/clair"
|
||||||
"github.com/vmware/harbor/src/common/models"
|
"github.com/vmware/harbor/src/common/models"
|
||||||
"github.com/vmware/harbor/src/common/utils"
|
"github.com/vmware/harbor/src/common/utils"
|
||||||
"github.com/vmware/harbor/src/common/utils/log"
|
"github.com/vmware/harbor/src/common/utils/log"
|
||||||
@ -105,8 +106,14 @@ func (n *NotificationHandler) Post() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go api.TriggerReplicationByRepository(pro.ProjectID, repository, []string{tag}, models.RepOpTransfer)
|
go api.TriggerReplicationByRepository(pro.ProjectID, repository, []string{tag}, models.RepOpTransfer)
|
||||||
|
|
||||||
if autoScanEnabled(project) {
|
if autoScanEnabled(project) {
|
||||||
if err := uiutils.TriggerImageScan(repository, tag); err != nil {
|
last, err := clairdao.GetLastUpdate()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get last update from Clair DB, error: %v, the auto scan will be skipped.", err)
|
||||||
|
} else if last == 0 {
|
||||||
|
log.Infof("The Vulnerability data is not ready in Clair DB, the auto scan will be skipped.", err)
|
||||||
|
} else if err := uiutils.TriggerImageScan(repository, tag); err != nil {
|
||||||
log.Warningf("Failed to scan image, repository: %s, tag: %s, error: %v", repository, tag, err)
|
log.Warningf("Failed to scan image, repository: %s, tag: %s, error: %v", repository, tag, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export const ENDPOINT_TEMPLATE: string = `
|
|||||||
<clr-dg-cell>{{t.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{t.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'DESTINATION.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}} {{'DESTINATION.ITEMS' | translate}}
|
{{pagination.totalItems}} {{'DESTINATION.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -34,7 +34,7 @@ export const LIST_REPLICATION_RULE_TEMPLATE: string = `
|
|||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} {{pagination.totalItems }} {{'REPLICATION.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPLICATION.OF' | translate}} </span>{{pagination.totalItems }} {{'REPLICATION.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
|
@ -13,7 +13,7 @@ export const LIST_REPOSITORY_TEMPLATE = `
|
|||||||
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
|
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}}{{'REPOSITORY.ITEMS' | translate}}
|
{{pagination.totalItems}}{{'REPOSITORY.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -67,7 +67,7 @@ export const REPLICATION_TEMPLATE: string = `
|
|||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPLICATION.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}
|
{{pagination.totalItems}} {{'REPLICATION.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="5"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -30,7 +30,7 @@ export const REPOSITORY_STACKVIEW_TEMPLATE: string = `
|
|||||||
<clr-icon shape="warning" class="is-warning" size="24"></clr-icon>
|
<clr-icon shape="warning" class="is-warning" size="24"></clr-icon>
|
||||||
{{'CONFIG.SCANNING.DB_NOT_READY' | translate }}
|
{{'CONFIG.SCANNING.DB_NOT_READY' | translate }}
|
||||||
</span>
|
</span>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
|
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [(clrDgPage)]="currentPage" [clrDgPageSize]="pageSize" [clrDgTotalItems]="totalCount"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -36,7 +36,7 @@ export abstract class EndpointService {
|
|||||||
* @abstract
|
* @abstract
|
||||||
* @param {(number | string)} endpointId
|
* @param {(number | string)} endpointId
|
||||||
* @returns {(Observable<Endpoint> | Endpoint)}
|
* @returns {(Observable<Endpoint> | Endpoint)}
|
||||||
*
|
*
|
||||||
* @memberOf EndpointService
|
* @memberOf EndpointService
|
||||||
*/
|
*/
|
||||||
abstract getEndpoint(endpointId: number | string): Observable<Endpoint> | Promise<Endpoint> | Endpoint;
|
abstract getEndpoint(endpointId: number | string): Observable<Endpoint> | Promise<Endpoint> | Endpoint;
|
||||||
@ -185,14 +185,16 @@ export class EndpointDefaultService extends EndpointService {
|
|||||||
if(!endpoint) {
|
if(!endpoint) {
|
||||||
return Promise.reject('Invalid endpoint.');
|
return Promise.reject('Invalid endpoint.');
|
||||||
}
|
}
|
||||||
let requestUrl: string = `${this._endpointUrl}/ping`;
|
let requestUrl: string ;
|
||||||
if(endpoint.id) {
|
if(endpoint.id) {
|
||||||
|
requestUrl = `${this._endpointUrl}/${endpoint.id}/ping`;
|
||||||
return this.http
|
return this.http
|
||||||
.post(requestUrl, {})
|
.post(requestUrl, {})
|
||||||
.toPromise()
|
.toPromise()
|
||||||
.then(response=>response.status)
|
.then(response=>response.status)
|
||||||
.catch(error=>Promise.reject(error));
|
.catch(error=>Promise.reject(error));
|
||||||
} else {
|
} else {
|
||||||
|
requestUrl = `${this._endpointUrl}/ping`;
|
||||||
return this.http
|
return this.http
|
||||||
.post(requestUrl, endpoint)
|
.post(requestUrl, endpoint)
|
||||||
.toPromise()
|
.toPromise()
|
||||||
|
@ -53,7 +53,7 @@ export const TAG_TEMPLATE = `
|
|||||||
<clr-dg-cell style="width: 80px;" *ngIf="!withClair">{{t.os}}</clr-dg-cell>
|
<clr-dg-cell style="width: 80px;" *ngIf="!withClair">{{t.os}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'REPOSITORY.OF' | translate}}</span>
|
||||||
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
|
{{pagination.totalItems}} {{'REPOSITORY.ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="10"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="10"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
|
@ -78,7 +78,8 @@ export const GRID_COMPONENT_HTML: string = `
|
|||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'VULNERABILITY.GRID.FOOT_OF' | translate}} {{pagination.totalItems}} {{'VULNERABILITY.GRID.FOOT_ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'VULNERABILITY.GRID.FOOT_OF' | translate}}</span>
|
||||||
|
{{pagination.totalItems}} {{'VULNERABILITY.GRID.FOOT_ITEMS' | translate}}
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="25" [clrDgTotalItems]="scanningResults.length"></clr-dg-pagination>
|
<clr-dg-pagination #pagination [clrDgPageSize]="25" [clrDgTotalItems]="scanningResults.length"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<label for="tabsystem">{{'SIDE_NAV.SYSTEM_MGMT.NAME' | translate}}</label>
|
<label for="tabsystem">{{'SIDE_NAV.SYSTEM_MGMT.NAME' | translate}}</label>
|
||||||
<ul class="nav-list">
|
<ul class="nav-list">
|
||||||
<li><a class="nav-link nav-link-override" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
|
<li><a class="nav-link nav-link-override" routerLink="/harbor/users" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}</a></li>
|
||||||
<li><a class="nav-link nav-link-override" routerLink="/harbor/replications/endpoints" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
|
<li><a class="nav-link nav-link-override" routerLink="/harbor/replications" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.REPLICATION' | translate}}</a></li>
|
||||||
<li><a class="nav-link nav-link-override" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
|
<li><a class="nav-link nav-link-override" routerLink="/harbor/configs" routerLinkActive="active">{{'SIDE_NAV.SYSTEM_MGMT.CONFIG' | translate}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -90,6 +90,10 @@ const harborRoutes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'endpoints',
|
path: 'endpoints',
|
||||||
component: DestinationPageComponent
|
component: DestinationPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
redirectTo: 'endpoints'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -56,8 +56,11 @@
|
|||||||
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{l.op_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{totalRecordCount}} {{'AUDIT_LOG.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'AUDIT_LOG.OF' | translate}} </span>
|
||||||
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination>
|
{{pagination.totalItems }} {{'AUDIT_LOG.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
|
<!--{{totalRecordCount}} {{'AUDIT_LOG.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination [clrDgPageSize]="pageOffset" [clrDgTotalItems]="totalPage"></clr-dg-pagination>-->
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,7 +54,7 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
createProjectOpened: boolean;
|
createProjectOpened: boolean;
|
||||||
|
|
||||||
hasChanged: boolean;
|
hasChanged: boolean;
|
||||||
btnIsOk:boolean=false;
|
isSubmitOnGoing:boolean=false;
|
||||||
|
|
||||||
staticBackdrop: boolean = true;
|
staticBackdrop: boolean = true;
|
||||||
closable: boolean = false;
|
closable: boolean = false;
|
||||||
@ -86,12 +86,10 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
this.isNameValid = cont.valid;
|
this.isNameValid = cont.valid;
|
||||||
if (this.isNameValid) {
|
if (this.isNameValid) {
|
||||||
//Check exiting from backend
|
//Check exiting from backend
|
||||||
this.checkOnGoing = true;
|
|
||||||
this.projectService
|
this.projectService
|
||||||
.checkProjectExists(cont.value).toPromise()
|
.checkProjectExists(cont.value).toPromise()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
//Project existing
|
//Project existing
|
||||||
this.btnIsOk=true;
|
|
||||||
this.isNameValid = false;
|
this.isNameValid = false;
|
||||||
this.nameTooltipText = 'PROJECT.NAME_ALREADY_EXISTS';
|
this.nameTooltipText = 'PROJECT.NAME_ALREADY_EXISTS';
|
||||||
this.checkOnGoing = false;
|
this.checkOnGoing = false;
|
||||||
@ -111,16 +109,24 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.btnIsOk=false;
|
if (this.isSubmitOnGoing){
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isSubmitOnGoing=true;
|
||||||
this.projectService
|
this.projectService
|
||||||
.createProject(this.project.name, this.project.public ? 1 : 0)
|
.createProject(this.project.name, this.project.public ? 1 : 0)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
status => {
|
status => {
|
||||||
|
this.isSubmitOnGoing=false;
|
||||||
|
|
||||||
this.create.emit(true);
|
this.create.emit(true);
|
||||||
this.messageHandlerService.showSuccess('PROJECT.CREATED_SUCCESS');
|
this.messageHandlerService.showSuccess('PROJECT.CREATED_SUCCESS');
|
||||||
this.createProjectOpened = false;
|
this.createProjectOpened = false;
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
this.isSubmitOnGoing=false;
|
||||||
|
|
||||||
let errorMessage: string;
|
let errorMessage: string;
|
||||||
if (error instanceof Response) {
|
if (error instanceof Response) {
|
||||||
switch (error.status) {
|
switch (error.status) {
|
||||||
@ -187,7 +193,7 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
public get isValid(): boolean {
|
public get isValid(): boolean {
|
||||||
return this.currentForm &&
|
return this.currentForm &&
|
||||||
this.currentForm.valid &&
|
this.currentForm.valid &&
|
||||||
this.btnIsOk&&
|
!this.isSubmitOnGoing&&
|
||||||
this.isNameValid &&
|
this.isNameValid &&
|
||||||
!this.checkOnGoing;
|
!this.checkOnGoing;
|
||||||
}
|
}
|
||||||
@ -198,6 +204,7 @@ export class CreateProjectComponent implements AfterViewChecked, OnInit, OnDestr
|
|||||||
if (cont) {
|
if (cont) {
|
||||||
this.proNameChecker.next(cont.value);
|
this.proNameChecker.next(cont.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span>
|
||||||
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
{{pagination.totalItems }} {{'PROJECT.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
@ -27,7 +27,11 @@
|
|||||||
<clr-dg-cell>{{m.username}}</clr-dg-cell>
|
<clr-dg-cell>{{m.username}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{roleInfo[m.role_id] | translate}}</clr-dg-cell>
|
<clr-dg-cell>{{roleInfo[m.role_id] | translate}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>{{ (members ? members.length : 0) }} {{'MEMBER.ITEMS' | translate}}</clr-dg-footer>
|
<clr-dg-footer>
|
||||||
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'MEMBER.OF' | translate}} </span>
|
||||||
|
{{pagination.totalItems }} {{'MEMBER.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -10,7 +10,10 @@
|
|||||||
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{p.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'PROJECT.OF' | translate}} </span>
|
||||||
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
{{pagination.totalItems }} {{'PROJECT.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
|
<!--{{(projects ? projects.length : 0)}} {{'PROJECT.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>-->
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
@ -8,7 +8,8 @@
|
|||||||
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
|
<clr-dg-cell>{{r.pull_count}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
{{(repositories ? repositories.length : 0)}} {{'REPOSITORY.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem +1 }} {{'REPOSITORY.OF' | translate}} </span>
|
||||||
<clr-dg-pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
{{pagination.totalItems }} {{'REPOSITORY.ITEMS' | translate}}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15"></clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
@ -27,8 +27,10 @@
|
|||||||
<clr-dg-cell>{{user.email}}</clr-dg-cell>
|
<clr-dg-cell>{{user.email}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{user.creation_time | date: 'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{user.creation_time | date: 'short'}}</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
<clr-dg-footer>{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} of {{pagination.totalItems}} users
|
<clr-dg-footer>
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="15" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount"> {{'USER.ITEMS' | translate}}
|
<span *ngIf="pagination.totalItems">{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} {{'USER.OF' | translate }}</span>
|
||||||
|
{{pagination.totalItems}} {{'USER.ITEMS' | translate }}
|
||||||
|
<clr-dg-pagination #pagination [clrDgPageSize]="15" [(clrDgPage)]="currentPage" [clrDgTotalItems]="totalCount">
|
||||||
</clr-dg-pagination>
|
</clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"DELETION_TITLE": "Confirm user deletion",
|
"DELETION_TITLE": "Confirm user deletion",
|
||||||
"DELETION_SUMMARY": "Do you want to delete user {{param}}?",
|
"DELETION_SUMMARY": "Do you want to delete user {{param}}?",
|
||||||
"DELETE_SUCCESS": "User deleted successfully.",
|
"DELETE_SUCCESS": "User deleted successfully.",
|
||||||
"ITEMS": "item(s)"
|
"ITEMS": "items"
|
||||||
},
|
},
|
||||||
"PROJECT": {
|
"PROJECT": {
|
||||||
"PROJECTS": "Projects",
|
"PROJECTS": "Projects",
|
||||||
@ -143,7 +143,7 @@
|
|||||||
"NAME_ALREADY_EXISTS": "Project name already exists.",
|
"NAME_ALREADY_EXISTS": "Project name already exists.",
|
||||||
"NAME_IS_ILLEGAL": "Project name is invalid.",
|
"NAME_IS_ILLEGAL": "Project name is invalid.",
|
||||||
"UNKNOWN_ERROR": "An unknown error occurred while creating the project.",
|
"UNKNOWN_ERROR": "An unknown error occurred while creating the project.",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"DELETION_TITLE": "Confirm project deletion",
|
"DELETION_TITLE": "Confirm project deletion",
|
||||||
"DELETION_SUMMARY": "Do you want to delete project {{param}}?",
|
"DELETION_SUMMARY": "Do you want to delete project {{param}}?",
|
||||||
"FILTER_PLACEHOLDER": "Filter Projects",
|
"FILTER_PLACEHOLDER": "Filter Projects",
|
||||||
@ -171,7 +171,7 @@
|
|||||||
"DEVELOPER": "Developer",
|
"DEVELOPER": "Developer",
|
||||||
"GUEST": "Guest",
|
"GUEST": "Guest",
|
||||||
"DELETE": "Delete",
|
"DELETE": "Delete",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"ACTIONS": "Actions",
|
"ACTIONS": "Actions",
|
||||||
"USERNAME_IS_REQUIRED": "Username is required",
|
"USERNAME_IS_REQUIRED": "Username is required",
|
||||||
"USERNAME_DOES_NOT_EXISTS": "Username does not exist.",
|
"USERNAME_DOES_NOT_EXISTS": "Username does not exist.",
|
||||||
@ -199,7 +199,7 @@
|
|||||||
"OTHERS": "Others",
|
"OTHERS": "Others",
|
||||||
"ADVANCED": "Advanced",
|
"ADVANCED": "Advanced",
|
||||||
"SIMPLE": "Simple",
|
"SIMPLE": "Simple",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"FILTER_PLACEHOLDER": "Filter Logs",
|
"FILTER_PLACEHOLDER": "Filter Logs",
|
||||||
"INVALID_DATE": "Invalid date."
|
"INVALID_DATE": "Invalid date."
|
||||||
},
|
},
|
||||||
@ -257,7 +257,7 @@
|
|||||||
"END_TIME": "End Time",
|
"END_TIME": "End Time",
|
||||||
"LOGS": "Logs",
|
"LOGS": "Logs",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"TOGGLE_ENABLE_TITLE": "Enable Rule",
|
"TOGGLE_ENABLE_TITLE": "Enable Rule",
|
||||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. \nPlease confirm to continue.",
|
"CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. \nPlease confirm to continue.",
|
||||||
"TOGGLE_DISABLE_TITLE": "Disable Rule",
|
"TOGGLE_DISABLE_TITLE": "Disable Rule",
|
||||||
@ -296,7 +296,7 @@
|
|||||||
"FAILED_TO_GET_TARGET": "Failed to get endpoint.",
|
"FAILED_TO_GET_TARGET": "Failed to get endpoint.",
|
||||||
"CREATION_TIME": "Creation Time",
|
"CREATION_TIME": "Creation Time",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"CREATED_SUCCESS": "Created endpoint successfully.",
|
"CREATED_SUCCESS": "Created endpoint successfully.",
|
||||||
"UPDATED_SUCCESS": "Updated endpoint successfully.",
|
"UPDATED_SUCCESS": "Updated endpoint successfully.",
|
||||||
"DELETED_SUCCESS": "Deleted endpoint successfully.",
|
"DELETED_SUCCESS": "Deleted endpoint successfully.",
|
||||||
@ -331,7 +331,7 @@
|
|||||||
"SHOW_DETAILS": "Show Details",
|
"SHOW_DETAILS": "Show Details",
|
||||||
"REPOSITORIES": "Repositories",
|
"REPOSITORIES": "Repositories",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "item(s)",
|
"ITEMS": "items",
|
||||||
"POP_REPOS": "Popular Repositories",
|
"POP_REPOS": "Popular Repositories",
|
||||||
"DELETED_REPO_SUCCESS": "Deleted repository successfully.",
|
"DELETED_REPO_SUCCESS": "Deleted repository successfully.",
|
||||||
"DELETED_TAG_SUCCESS": "Deleted tag successfully.",
|
"DELETED_TAG_SUCCESS": "Deleted tag successfully.",
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"DELETION_TITLE": "Confirmar eliminación de usuario",
|
"DELETION_TITLE": "Confirmar eliminación de usuario",
|
||||||
"DELETION_SUMMARY": "¿Quiere eliminar el usuario {{param}}?",
|
"DELETION_SUMMARY": "¿Quiere eliminar el usuario {{param}}?",
|
||||||
"DELETE_SUCCESS": "Usuario eliminado satisfactoriamente.",
|
"DELETE_SUCCESS": "Usuario eliminado satisfactoriamente.",
|
||||||
"ITEMS": "elemento(s)"
|
"ITEMS": "elementos"
|
||||||
},
|
},
|
||||||
"PROJECT": {
|
"PROJECT": {
|
||||||
"PROJECTS": "Proyectos",
|
"PROJECTS": "Proyectos",
|
||||||
@ -143,7 +143,7 @@
|
|||||||
"NAME_ALREADY_EXISTS": "Ya existe un proyecto con ese nombre.",
|
"NAME_ALREADY_EXISTS": "Ya existe un proyecto con ese nombre.",
|
||||||
"NAME_IS_ILLEGAL": "El nombre del proyecto no es valido.",
|
"NAME_IS_ILLEGAL": "El nombre del proyecto no es valido.",
|
||||||
"UNKNOWN_ERROR": "Ha ocurrido un error al crear el proyecto.",
|
"UNKNOWN_ERROR": "Ha ocurrido un error al crear el proyecto.",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"DELETION_TITLE": "Confirmar eliminación del proyecto",
|
"DELETION_TITLE": "Confirmar eliminación del proyecto",
|
||||||
"DELETION_SUMMARY": "¿Quiere eliminar el proyecto {{param}}?",
|
"DELETION_SUMMARY": "¿Quiere eliminar el proyecto {{param}}?",
|
||||||
"FILTER_PLACEHOLDER": "Filtrar proyectos",
|
"FILTER_PLACEHOLDER": "Filtrar proyectos",
|
||||||
@ -171,7 +171,7 @@
|
|||||||
"DEVELOPER": "Desarrollador",
|
"DEVELOPER": "Desarrollador",
|
||||||
"GUEST": "Invitado",
|
"GUEST": "Invitado",
|
||||||
"DELETE": "Eliminar",
|
"DELETE": "Eliminar",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"ACTIONS": "Acciones",
|
"ACTIONS": "Acciones",
|
||||||
"USERNAME_IS_REQUIRED": "El nombre de usuario es obligatorio",
|
"USERNAME_IS_REQUIRED": "El nombre de usuario es obligatorio",
|
||||||
"USERNAME_DOES_NOT_EXISTS": "Ese nombre de usuario no existe.",
|
"USERNAME_DOES_NOT_EXISTS": "Ese nombre de usuario no existe.",
|
||||||
@ -199,7 +199,7 @@
|
|||||||
"OTHERS": "Otros",
|
"OTHERS": "Otros",
|
||||||
"ADVANCED": "Avanzado",
|
"ADVANCED": "Avanzado",
|
||||||
"SIMPLE": "Simple",
|
"SIMPLE": "Simple",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"FILTER_PLACEHOLDER": "Filtrar logs",
|
"FILTER_PLACEHOLDER": "Filtrar logs",
|
||||||
"INVALID_DATE": "Fecha invalida."
|
"INVALID_DATE": "Fecha invalida."
|
||||||
},
|
},
|
||||||
@ -257,7 +257,7 @@
|
|||||||
"END_TIME": "Fecha de Finalización",
|
"END_TIME": "Fecha de Finalización",
|
||||||
"LOGS": "Logs",
|
"LOGS": "Logs",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"TOGGLE_ENABLE_TITLE": "Activar Regla",
|
"TOGGLE_ENABLE_TITLE": "Activar Regla",
|
||||||
"CONFIRM_TOGGLE_ENABLE_POLICY": "Después de la activación de esta regla, todos los repositorios de este proyecto serán replicados al registro de destino.\nPor favor, confirme para continuar.",
|
"CONFIRM_TOGGLE_ENABLE_POLICY": "Después de la activación de esta regla, todos los repositorios de este proyecto serán replicados al registro de destino.\nPor favor, confirme para continuar.",
|
||||||
"TOGGLE_DISABLE_TITLE": "Desactivar Regla",
|
"TOGGLE_DISABLE_TITLE": "Desactivar Regla",
|
||||||
@ -296,7 +296,7 @@
|
|||||||
"FAILED_TO_GET_TARGET": "Fallo al obtener el endpoint.",
|
"FAILED_TO_GET_TARGET": "Fallo al obtener el endpoint.",
|
||||||
"CREATION_TIME": "Fecha de creación",
|
"CREATION_TIME": "Fecha de creación",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"CREATED_SUCCESS": "Endpoint creado satisfactoriamente.",
|
"CREATED_SUCCESS": "Endpoint creado satisfactoriamente.",
|
||||||
"UPDATED_SUCCESS": "Endpoint actualizado satisfactoriamente.",
|
"UPDATED_SUCCESS": "Endpoint actualizado satisfactoriamente.",
|
||||||
"DELETED_SUCCESS": "Endpoint eliminado satisfactoriamente.",
|
"DELETED_SUCCESS": "Endpoint eliminado satisfactoriamente.",
|
||||||
@ -332,7 +332,7 @@
|
|||||||
"SHOW_DETAILS": "Mostrar Detalles",
|
"SHOW_DETAILS": "Mostrar Detalles",
|
||||||
"REPOSITORIES": "Repositorios",
|
"REPOSITORIES": "Repositorios",
|
||||||
"OF": "of",
|
"OF": "of",
|
||||||
"ITEMS": "elemento(s)",
|
"ITEMS": "elementos",
|
||||||
"POP_REPOS": "Repositorios Populares",
|
"POP_REPOS": "Repositorios Populares",
|
||||||
"DELETED_REPO_SUCCESS": "Repositorio eliminado satisfactoriamente.",
|
"DELETED_REPO_SUCCESS": "Repositorio eliminado satisfactoriamente.",
|
||||||
"DELETED_TAG_SUCCESS": "Etiqueta eliminada satisfactoriamente.",
|
"DELETED_TAG_SUCCESS": "Etiqueta eliminada satisfactoriamente.",
|
||||||
|
@ -117,6 +117,7 @@
|
|||||||
"DELETION_TITLE": "删除用户确认",
|
"DELETION_TITLE": "删除用户确认",
|
||||||
"DELETION_SUMMARY": "你确认删除用户 {{param}}?",
|
"DELETION_SUMMARY": "你确认删除用户 {{param}}?",
|
||||||
"DELETE_SUCCESS": "成功删除用户。",
|
"DELETE_SUCCESS": "成功删除用户。",
|
||||||
|
"OF": "共计",
|
||||||
"ITEMS": "条记录"
|
"ITEMS": "条记录"
|
||||||
},
|
},
|
||||||
"PROJECT": {
|
"PROJECT": {
|
||||||
@ -143,6 +144,7 @@
|
|||||||
"NAME_ALREADY_EXISTS": "项目名称已存在。",
|
"NAME_ALREADY_EXISTS": "项目名称已存在。",
|
||||||
"NAME_IS_ILLEGAL": "项目名称非法。",
|
"NAME_IS_ILLEGAL": "项目名称非法。",
|
||||||
"UNKNOWN_ERROR": "创建项目时发生未知错误。",
|
"UNKNOWN_ERROR": "创建项目时发生未知错误。",
|
||||||
|
"OF": "共计",
|
||||||
"ITEMS": "条记录",
|
"ITEMS": "条记录",
|
||||||
"DELETION_TITLE": "删除项目确认",
|
"DELETION_TITLE": "删除项目确认",
|
||||||
"DELETION_SUMMARY": "你确认删除项目 {{param}}?",
|
"DELETION_SUMMARY": "你确认删除项目 {{param}}?",
|
||||||
@ -171,6 +173,7 @@
|
|||||||
"DEVELOPER": "开发人员",
|
"DEVELOPER": "开发人员",
|
||||||
"GUEST": "访客",
|
"GUEST": "访客",
|
||||||
"DELETE": "删除",
|
"DELETE": "删除",
|
||||||
|
"OF": "共计",
|
||||||
"ITEMS": "条记录",
|
"ITEMS": "条记录",
|
||||||
"ACTIONS": "操作",
|
"ACTIONS": "操作",
|
||||||
"USERNAME_IS_REQUIRED": "用户名为必填项。",
|
"USERNAME_IS_REQUIRED": "用户名为必填项。",
|
||||||
@ -199,6 +202,7 @@
|
|||||||
"OTHERS": "其他",
|
"OTHERS": "其他",
|
||||||
"ADVANCED": "高级检索",
|
"ADVANCED": "高级检索",
|
||||||
"SIMPLE": "简单检索",
|
"SIMPLE": "简单检索",
|
||||||
|
"OF": "共计",
|
||||||
"ITEMS": "条记录",
|
"ITEMS": "条记录",
|
||||||
"FILTER_PLACEHOLDER": "过滤日志",
|
"FILTER_PLACEHOLDER": "过滤日志",
|
||||||
"INVALID_DATE": "无效日期。"
|
"INVALID_DATE": "无效日期。"
|
||||||
|
Loading…
Reference in New Issue
Block a user