@ -31,6 +31,7 @@ env:
|
||||
|
||||
before_install:
|
||||
- sudo ./tests/hostcfg.sh
|
||||
- sudo ./tests/generateCerts.sh
|
||||
- sudo ./make/prepare
|
||||
|
||||
install:
|
||||
@ -92,12 +93,12 @@ script:
|
||||
- goveralls -coverprofile=profile.cov -service=travis-ci
|
||||
|
||||
- docker-compose -f make/docker-compose.test.yml down
|
||||
- sudo make/prepare
|
||||
- sudo rm -rf /data/config/*
|
||||
- docker-compose -f make/dev/docker-compose.yml up -d
|
||||
- sudo rm -rf /data/config/*
|
||||
- ls /data/cert
|
||||
- sudo make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=danieljt/harbor-clarity-base:0.8.4 NOTARYFLAG=true
|
||||
|
||||
- docker ps
|
||||
- go run tests/startuptest.go http://localhost/
|
||||
- go run tests/startuptest.go https://localhost/
|
||||
- go run tests/userlogintest.go -name ${HARBOR_ADMIN} -passwd ${HARBOR_ADMIN_PASSWD}
|
||||
|
||||
# - sudo ./tests/testprepare.sh
|
||||
|
32
Makefile
@ -80,6 +80,12 @@ REGISTRYPROJECTNAME=vmware
|
||||
DEVFLAG=true
|
||||
NOTARYFLAG=false
|
||||
REGISTRYVERSION=2.6.0
|
||||
NGINXVERSION=1.11.5
|
||||
PHOTONVERSION=1.0
|
||||
NOTARYVERSION=server-0.5.0-fix
|
||||
NOTARYSIGNERVERSION=signer-0.5.0
|
||||
MARIADBVERSION=10.1.10
|
||||
HTTPPROXY=
|
||||
|
||||
#clarity parameters
|
||||
CLARITYIMAGE=danieljt/harbor-clarity-base[:tag]
|
||||
@ -207,7 +213,11 @@ compile_jobservice:
|
||||
|
||||
compile_clarity:
|
||||
@echo "compiling binary for clarity ui..."
|
||||
@$(DOCKERCMD) run --rm -v $(UIPATH)/static/new-ui:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src -v $(UINGPATH)/src/app:$(CLARITYSEEDPATH)/src/app $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT)
|
||||
@if [ "$(HTTPPROXY)" != "" ] ; then \
|
||||
$(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT) -p $(HTTPPROXY); \
|
||||
else \
|
||||
$(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT); \
|
||||
fi
|
||||
@echo "Done."
|
||||
|
||||
compile_normal: compile_clarity compile_adminserver compile_ui compile_jobservice
|
||||
@ -292,12 +302,12 @@ package_offline: compile build modify_composefile
|
||||
|
||||
@echo "pulling nginx and registry..."
|
||||
@$(DOCKERPULL) registry:$(REGISTRYVERSION)
|
||||
@$(DOCKERPULL) nginx:1.11.5
|
||||
@$(DOCKERPULL) nginx:$(NGINXVERSION)
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
echo "pulling notary and mariadb..."; \
|
||||
$(DOCKERPULL) jiangd/notary:server-0.5.0-fix; \
|
||||
$(DOCKERPULL) notary:signer-0.5.0; \
|
||||
$(DOCKERPULL) mariadb:10.1.10; \
|
||||
$(DOCKERPULL) jiangd/notary:$(NOTARYVERSION); \
|
||||
$(DOCKERPULL) notary:$(NOTARYSIGNERVERSION); \
|
||||
$(DOCKERPULL) mariadb:$(MARIADBVERSION); \
|
||||
fi
|
||||
|
||||
@echo "saving harbor docker image"
|
||||
@ -308,8 +318,8 @@ package_offline: compile build modify_composefile
|
||||
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
nginx:1.11.5 registry:$(REGISTRYVERSION) photon:1.0 \
|
||||
jiangd/notary:server-0.5.0-fix notary:signer-0.5.0 mariadb:10.1.10; \
|
||||
nginx:$(NGINXVERSION) registry:$(REGISTRYVERSION) photon:$(PHOTONVERSION) \
|
||||
jiangd/notary:$(NOTARYVERSION) notary:$(NOTARYSIGNERVERSION) mariadb:$(MARIADBVERSION); \
|
||||
else \
|
||||
$(DOCKERSAVE) -o $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tgz \
|
||||
$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
|
||||
@ -317,7 +327,7 @@ package_offline: compile build modify_composefile
|
||||
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
nginx:1.11.5 registry:$(REGISTRYVERSION) photon:1.0 ; \
|
||||
nginx:$(NGINXVERSION) registry:$(REGISTRYVERSION) photon:$(PHOTONVERSION) ; \
|
||||
fi
|
||||
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
@ -325,14 +335,14 @@ package_offline: compile build modify_composefile
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tgz \
|
||||
$(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) ; \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
|
||||
$(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME) ; \
|
||||
else \
|
||||
$(TARCMD) -zcvf harbor-offline-installer-$(VERSIONTAG).tgz \
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tgz \
|
||||
$(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
|
||||
$(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME) ; \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) ; \
|
||||
fi
|
||||
|
||||
@rm -rf $(HARBORPKG)
|
||||
|
@ -1,12 +1,18 @@
|
||||
FROM node:7.5.0
|
||||
|
||||
COPY angular-cli.json /
|
||||
COPY index.html /
|
||||
COPY entrypoint.sh /
|
||||
RUN mkdir -p /clarity-seed
|
||||
|
||||
RUN npm install -g @angular/cli && \
|
||||
chmod u+x entrypoint.sh
|
||||
COPY src/ui_ng/package.json /clarity-seed
|
||||
COPY src/ui_ng/tslint.json /clarity-seed
|
||||
COPY src/ui_ng/typings.json /clarity-seed
|
||||
COPY src/ui_ng/yarn.lock /clarity-seed
|
||||
COPY make/dev/nodeclarity/angular-cli.json /clarity-seed
|
||||
COPY make/dev/nodeclarity/entrypoint.sh /
|
||||
|
||||
VOLUME ["/clarity-seed", "/clarity-seed/dist"]
|
||||
WORKDIR /clarity-seed
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
RUN npm install -g @angular/cli && \
|
||||
npm install && \
|
||||
chmod u+x /entrypoint.sh
|
||||
|
||||
VOLUME ["/clarity-seed", "/clarity-seed/dist"]
|
@ -1,11 +1,25 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd /clarity-seed
|
||||
rm -rf dist/*
|
||||
cp /angular-cli.json /clarity-seed
|
||||
|
||||
npm_proxy=
|
||||
|
||||
while getopts p: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
p) npm_proxy=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -z "$npm_proxy" -a "$npm_proxy" != " " ]; then
|
||||
npm config set proxy $npm_proxy
|
||||
fi
|
||||
|
||||
npm install
|
||||
ng build
|
||||
|
||||
cp /index.html dist/index.html
|
||||
cp -r ./src/i18n/ dist/
|
||||
|
||||
|
@ -14,12 +14,8 @@ ENV MYSQL_USR root \
|
||||
COPY src/ui/views /go/bin/views
|
||||
COPY src/ui/static /go/bin/static
|
||||
COPY src/favicon.ico /go/bin/favicon.ico
|
||||
COPY make/jsminify.sh /tmp/jsminify.sh
|
||||
|
||||
RUN chmod u+x /go/bin/harbor_ui \
|
||||
&& timestamp=`date '+%s'` \
|
||||
&& /tmp/jsminify.sh /go/bin/views/sections/script-include.htm /go/bin/static/resources/js/harbor.app.min.$timestamp.js /go/bin/ \
|
||||
&& sed -i "s/harbor\.app\.min\.js/harbor\.app\.min\.$timestamp\.js/g" /go/bin/views/sections/script-min-include.htm
|
||||
RUN chmod u+x /go/bin/harbor_ui
|
||||
|
||||
WORKDIR /go/bin/
|
||||
ENTRYPOINT ["/go/bin/harbor_ui"]
|
||||
|
@ -1,71 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "This shell will minify the Javascript in Harbor project."
|
||||
echo "Usage: #jsminify [src] [dest] [basedir]"
|
||||
|
||||
#prepare workspace
|
||||
rm -rf $2 /tmp/harbor.app.temp.js
|
||||
|
||||
if [ -z $3 ]
|
||||
then
|
||||
BASEPATH=/go/bin
|
||||
else
|
||||
BASEPATH=$3
|
||||
fi
|
||||
|
||||
#concat the js files from js include file
|
||||
echo "Concat js files..."
|
||||
|
||||
cat $1 | while read LINE || [[ -n $LINE ]]
|
||||
do
|
||||
if [ -n "$LINE" ]
|
||||
then
|
||||
TEMP="$BASEPATH""$LINE"
|
||||
cat `echo "$TEMP" | sed 's/<script src=\"//g' | sed 's/\"><\/script>//g'` >> /tmp/harbor.app.temp.js
|
||||
printf "\n" >> /tmp/harbor.app.temp.js
|
||||
fi
|
||||
done
|
||||
|
||||
# If you want run this script on Mac OS X,
|
||||
# I suggest you install gnu-sed (whth --with-default-names option).
|
||||
# $ brew install gnu-sed --with-default-names
|
||||
# Reference:
|
||||
# http://stackoverflow.com/a/27834828/3167471
|
||||
|
||||
#remove space
|
||||
echo "Remove space.."
|
||||
sed 's/ \+/ /g' -i /tmp/harbor.app.temp.js
|
||||
|
||||
#remove '//' and '/*'
|
||||
echo "Remove '//'and '/*' annotation..."
|
||||
sed '/^\/\//'d -i /tmp/harbor.app.temp.js
|
||||
sed '/\/\*/{/\*\//d;:a;N;/\*\//d;ba};s,//.*,,' -i /tmp/harbor.app.temp.js
|
||||
|
||||
cat > $2 << EOF
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
EOF
|
||||
|
||||
#remove '\n'
|
||||
echo "Remove CR ..."
|
||||
cat /tmp/harbor.app.temp.js | tr -d '\n' >> $2
|
||||
|
||||
#clear workspace
|
||||
rm -rf /tmp/harbor.app.temp.js
|
||||
|
||||
echo "Done."
|
||||
exit 0
|
||||
|
||||
|
@ -1,19 +1,14 @@
|
||||
FROM library/photon:1.0
|
||||
|
||||
RUN mkdir /harbor/
|
||||
RUN tdnf install -y sed
|
||||
|
||||
COPY ./make/dev/ui/harbor_ui /harbor/
|
||||
|
||||
COPY ./src/ui/views /harbor/views
|
||||
COPY ./src/ui/static /harbor/static
|
||||
COPY ./src/favicon.ico /harbor/favicon.ico
|
||||
COPY ./make/jsminify.sh /tmp/jsminify.sh
|
||||
|
||||
RUN chmod u+x /harbor/harbor_ui \
|
||||
&& timestamp=`date '+%s'` \
|
||||
&& /tmp/jsminify.sh /harbor/views/sections/script-include.htm /harbor/static/resources/js/harbor.app.min.$timestamp.js /harbor/ \
|
||||
&& sed -i "s/harbor\.app\.min\.js/harbor\.app\.min\.$timestamp\.js/g" /harbor/views/sections/script-min-include.htm
|
||||
RUN chmod u+x /harbor/harbor_ui
|
||||
|
||||
WORKDIR /harbor/
|
||||
ENTRYPOINT ["/harbor/harbor_ui"]
|
||||
|
@ -1,23 +0,0 @@
|
||||
package controllers
|
||||
|
||||
// AccountSettingController handles request to /account_setting
|
||||
type AccountSettingController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the account settings page
|
||||
func (asc *AccountSettingController) Get() {
|
||||
var isAdminForLdap bool
|
||||
sessionUserID, ok := asc.GetSession("userId").(int)
|
||||
if !ok {
|
||||
asc.Redirect("/", 302)
|
||||
}
|
||||
if ok && sessionUserID == 1 {
|
||||
isAdminForLdap = true
|
||||
}
|
||||
if asc.AuthMode == "db_auth" || isAdminForLdap {
|
||||
asc.Forward("page_title_account_setting", "account-settings.htm")
|
||||
} else {
|
||||
asc.Redirect("/dashboard", 302)
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// AddNewController handles requests to /add_new
|
||||
type AddNewController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the add new page
|
||||
func (anc *AddNewController) Get() {
|
||||
sessionUserID := anc.GetSession("userId")
|
||||
anc.Data["AddNew"] = false
|
||||
if sessionUserID != nil {
|
||||
isAdmin, err := dao.IsAdminRole(sessionUserID.(int))
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in IsAdminRole: %v", err)
|
||||
anc.CustomAbort(http.StatusInternalServerError, "")
|
||||
}
|
||||
if isAdmin && anc.AuthMode == "db_auth" {
|
||||
anc.Data["AddNew"] = true
|
||||
anc.Forward("page_title_add_new", "sign-up.htm")
|
||||
return
|
||||
}
|
||||
}
|
||||
anc.CustomAbort(http.StatusUnauthorized, "Status Unauthorized.")
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// AdminOptionController handles requests to /admin_option
|
||||
type AdminOptionController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the admin options page
|
||||
func (aoc *AdminOptionController) Get() {
|
||||
sessionUserID, ok := aoc.GetSession("userId").(int)
|
||||
if ok {
|
||||
isAdmin, err := dao.IsAdminRole(sessionUserID)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in IsAdminRole: %v", err)
|
||||
}
|
||||
if isAdmin {
|
||||
aoc.Forward("page_title_admin_option", "admin-options.htm")
|
||||
return
|
||||
}
|
||||
}
|
||||
aoc.Redirect("/dashboard", 302)
|
||||
}
|
@ -1,180 +1,27 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"regexp"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/beego/i18n"
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
"github.com/vmware/harbor/src/common/utils/email"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// BaseController wraps common methods such as i18n support, forward, which can be leveraged by other UI render controllers.
|
||||
type BaseController struct {
|
||||
beego.Controller
|
||||
i18n.Locale
|
||||
SelfRegistration bool
|
||||
IsAdmin bool
|
||||
AuthMode string
|
||||
UseCompressedJS bool
|
||||
}
|
||||
|
||||
type langType struct {
|
||||
Lang string
|
||||
Name string
|
||||
}
|
||||
|
||||
const (
|
||||
viewPath = "sections"
|
||||
prefixNg = ""
|
||||
defaultLang = "en-US"
|
||||
defaultRootCert = "/harbor_storage/ca_download/ca.crt"
|
||||
)
|
||||
|
||||
var supportLanguages map[string]langType
|
||||
var mappingLangNames map[string]string
|
||||
|
||||
// Prepare extracts the language information from request and populate data for rendering templates.
|
||||
func (b *BaseController) Prepare() {
|
||||
|
||||
var lang string
|
||||
var langHasChanged bool
|
||||
|
||||
var showDownloadCert bool
|
||||
|
||||
langRequest := b.GetString("lang")
|
||||
if langRequest != "" {
|
||||
lang = langRequest
|
||||
langHasChanged = true
|
||||
} else {
|
||||
langCookie, err := b.Ctx.Request.Cookie("language")
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in Request.Cookie: %v", err)
|
||||
}
|
||||
if langCookie != nil {
|
||||
lang = langCookie.Value
|
||||
} else {
|
||||
al := b.Ctx.Request.Header.Get("Accept-Language")
|
||||
if len(al) > 4 {
|
||||
al = al[:5] // Only compare first 5 letters.
|
||||
if i18n.IsExist(al) {
|
||||
lang = al
|
||||
}
|
||||
}
|
||||
langHasChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
if langHasChanged {
|
||||
if _, exist := supportLanguages[lang]; !exist { //Check if support the request language.
|
||||
lang = defaultLang //Set default language if not supported.
|
||||
}
|
||||
cookies := &http.Cookie{
|
||||
Name: "language",
|
||||
Value: lang,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
}
|
||||
http.SetCookie(b.Ctx.ResponseWriter, cookies)
|
||||
}
|
||||
|
||||
curLang := langType{
|
||||
Lang: lang,
|
||||
}
|
||||
|
||||
restLangs := make([]*langType, 0, len(langTypes)-1)
|
||||
for _, v := range langTypes {
|
||||
if lang != v.Lang {
|
||||
restLangs = append(restLangs, v)
|
||||
} else {
|
||||
curLang.Name = v.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Set language properties.
|
||||
b.Lang = lang
|
||||
b.Data["Lang"] = curLang.Lang
|
||||
b.Data["CurLang"] = curLang.Name
|
||||
b.Data["RestLangs"] = restLangs
|
||||
|
||||
authMode, err := config.AuthMode()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get auth mode: %v", err)
|
||||
b.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
if authMode == "" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
b.AuthMode = authMode
|
||||
b.Data["AuthMode"] = b.AuthMode
|
||||
|
||||
useCompressedJS := os.Getenv("USE_COMPRESSED_JS")
|
||||
if useCompressedJS == "on" {
|
||||
b.UseCompressedJS = true
|
||||
}
|
||||
|
||||
m, err := filepath.Glob(filepath.Join("static", "resources", "js", "harbor.app.min.*.js"))
|
||||
if err != nil || len(m) == 0 {
|
||||
b.UseCompressedJS = false
|
||||
}
|
||||
|
||||
b.SelfRegistration, err = config.SelfRegistration()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get self registration: %v", err)
|
||||
b.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
b.Data["SelfRegistration"] = b.SelfRegistration
|
||||
|
||||
sessionUserID := b.GetSession("userId")
|
||||
if sessionUserID != nil {
|
||||
isAdmin, err := dao.IsAdminRole(sessionUserID.(int))
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in IsAdminRole: %v", err)
|
||||
}
|
||||
if isAdmin {
|
||||
if _, err := os.Stat(defaultRootCert); !os.IsNotExist(err) {
|
||||
showDownloadCert = true
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Data["ShowDownloadCert"] = showDownloadCert
|
||||
}
|
||||
|
||||
// Forward to setup layout and template for content for a page.
|
||||
func (b *BaseController) Forward(title, templateName string) {
|
||||
b.Layout = filepath.Join(prefixNg, "layout.htm")
|
||||
b.TplName = filepath.Join(prefixNg, templateName)
|
||||
b.Data["Title"] = b.Tr(title)
|
||||
b.LayoutSections = make(map[string]string)
|
||||
b.LayoutSections["HeaderInclude"] = filepath.Join(prefixNg, viewPath, "header-include.htm")
|
||||
|
||||
if b.UseCompressedJS {
|
||||
b.LayoutSections["HeaderScriptInclude"] = filepath.Join(prefixNg, viewPath, "script-min-include.htm")
|
||||
} else {
|
||||
b.LayoutSections["HeaderScriptInclude"] = filepath.Join(prefixNg, viewPath, "script-include.htm")
|
||||
}
|
||||
|
||||
log.Debugf("Loaded HeaderScriptInclude file: %s", b.LayoutSections["HeaderScriptInclude"])
|
||||
|
||||
b.LayoutSections["FooterInclude"] = filepath.Join(prefixNg, viewPath, "footer-include.htm")
|
||||
b.LayoutSections["HeaderContent"] = filepath.Join(prefixNg, viewPath, "header-content.htm")
|
||||
b.LayoutSections["FooterContent"] = filepath.Join(prefixNg, viewPath, "footer-content.htm")
|
||||
|
||||
}
|
||||
|
||||
var langTypes []*langType
|
||||
|
||||
// CommonController handles request from UI that doesn't expect a page, such as /SwitchLanguage /logout ...
|
||||
type CommonController struct {
|
||||
BaseController
|
||||
beego.Controller
|
||||
i18n.Locale
|
||||
}
|
||||
|
||||
// Render returns nil.
|
||||
@ -182,6 +29,12 @@ func (cc *CommonController) Render() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type messageDetail struct {
|
||||
Hint string
|
||||
URL string
|
||||
UUID string
|
||||
}
|
||||
|
||||
// Login handles login request from UI.
|
||||
func (cc *CommonController) Login() {
|
||||
principal := cc.GetString("principal")
|
||||
@ -209,18 +62,6 @@ func (cc *CommonController) LogOut() {
|
||||
cc.DestroySession()
|
||||
}
|
||||
|
||||
// SwitchLanguage User can swith to prefered language
|
||||
func (cc *CommonController) SwitchLanguage() {
|
||||
lang := cc.GetString("lang")
|
||||
hash := cc.GetString("hash")
|
||||
if _, exist := supportLanguages[lang]; !exist {
|
||||
lang = defaultLang
|
||||
}
|
||||
cc.SetSession("lang", lang)
|
||||
cc.Data["Lang"] = lang
|
||||
cc.Redirect(cc.Ctx.Request.Header.Get("Referer")+hash, http.StatusFound)
|
||||
}
|
||||
|
||||
// UserExists checks if user exists when user input value in sign in form.
|
||||
func (cc *CommonController) UserExists() {
|
||||
target := cc.GetString("target")
|
||||
@ -243,6 +84,110 @@ func (cc *CommonController) UserExists() {
|
||||
cc.ServeJSON()
|
||||
}
|
||||
|
||||
// SendEmail verifies the Email address and contact SMTP server to send reset password Email.
|
||||
func (cc *CommonController) SendEmail() {
|
||||
|
||||
emailStr := cc.GetString("email")
|
||||
|
||||
pass, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`, emailStr)
|
||||
|
||||
if !pass {
|
||||
cc.CustomAbort(http.StatusBadRequest, "email_content_illegal")
|
||||
} else {
|
||||
|
||||
queryUser := models.User{Email: emailStr}
|
||||
exist, err := dao.UserExists(queryUser, "email")
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in UserExists: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
cc.CustomAbort(http.StatusNotFound, "email_does_not_exist")
|
||||
}
|
||||
|
||||
messageTemplate, err := template.ParseFiles("views/reset-password-mail.tpl")
|
||||
if err != nil {
|
||||
log.Errorf("Parse email template file failed: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
message := new(bytes.Buffer)
|
||||
|
||||
harborURL := config.ExtEndpoint
|
||||
if harborURL == "" {
|
||||
harborURL = "localhost"
|
||||
}
|
||||
uuid := utils.GenerateRandomString()
|
||||
err = messageTemplate.Execute(message, messageDetail{
|
||||
Hint: cc.Tr("reset_email_hint"),
|
||||
URL: harborURL,
|
||||
UUID: uuid,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Message template error: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
config, err := beego.AppConfig.GetSection("mail")
|
||||
if err != nil {
|
||||
log.Errorf("Can not load app.conf: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
mail := email.Mail{
|
||||
From: config["from"],
|
||||
To: []string{emailStr},
|
||||
Subject: cc.Tr("reset_email_subject"),
|
||||
Message: message.String()}
|
||||
|
||||
err = mail.SendMail()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Send email failed: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "send_email_failed")
|
||||
}
|
||||
|
||||
user := models.User{ResetUUID: uuid, Email: emailStr}
|
||||
dao.UpdateUserResetUUID(user)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ResetPassword handles request from the reset page and reset password
|
||||
func (cc *CommonController) ResetPassword() {
|
||||
|
||||
resetUUID := cc.GetString("reset_uuid")
|
||||
if resetUUID == "" {
|
||||
cc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
|
||||
}
|
||||
|
||||
queryUser := models.User{ResetUUID: resetUUID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if user == nil {
|
||||
log.Error("User does not exist")
|
||||
cc.CustomAbort(http.StatusBadRequest, "User does not exist")
|
||||
}
|
||||
|
||||
password := cc.GetString("password")
|
||||
|
||||
if password != "" {
|
||||
user.Password = password
|
||||
err = dao.ResetUserPassword(*user)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in ResetUserPassword: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
} else {
|
||||
cc.CustomAbort(http.StatusBadRequest, "password_is_required")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
//conf/app.conf -> os.Getenv("config_path")
|
||||
configPath := os.Getenv("CONFIG_PATH")
|
||||
@ -253,24 +198,4 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
beego.AddFuncMap("i18n", i18n.Tr)
|
||||
|
||||
langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
|
||||
names := strings.Split(beego.AppConfig.String("lang::names"), "|")
|
||||
|
||||
supportLanguages = make(map[string]langType)
|
||||
|
||||
langTypes = make([]*langType, 0, len(langs))
|
||||
|
||||
for i, lang := range langs {
|
||||
t := langType{
|
||||
Lang: lang,
|
||||
Name: names[i],
|
||||
}
|
||||
langTypes = append(langTypes, &t)
|
||||
supportLanguages[lang] = t
|
||||
if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil {
|
||||
log.Errorf("Fail to set message file: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package controllers
|
||||
|
||||
// ChangePasswordController handles request to /change_password
|
||||
type ChangePasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the change password page
|
||||
func (cpc *ChangePasswordController) Get() {
|
||||
var isAdminForLdap bool
|
||||
sessionUserID, ok := cpc.GetSession("userId").(int)
|
||||
if !ok {
|
||||
cpc.Redirect("/", 302)
|
||||
}
|
||||
if ok && sessionUserID == 1 {
|
||||
isAdminForLdap = true
|
||||
}
|
||||
if cpc.AuthMode == "db_auth" || isAdminForLdap {
|
||||
cpc.Forward("page_title_change_password", "change-password.htm")
|
||||
} else {
|
||||
cpc.Redirect("/dashboard", 302)
|
||||
}
|
||||
}
|
@ -42,29 +42,12 @@ func init() {
|
||||
beego.AddTemplateExt("htm")
|
||||
|
||||
beego.Router("/", &IndexController{})
|
||||
beego.Router("/dashboard", &DashboardController{})
|
||||
beego.Router("/project", &ProjectController{})
|
||||
beego.Router("/repository", &RepositoryController{})
|
||||
beego.Router("/sign_up", &SignUpController{})
|
||||
beego.Router("/add_new", &AddNewController{})
|
||||
beego.Router("/account_setting", &AccountSettingController{})
|
||||
beego.Router("/change_password", &ChangePasswordController{})
|
||||
beego.Router("/admin_option", &AdminOptionController{})
|
||||
beego.Router("/forgot_password", &ForgotPasswordController{})
|
||||
beego.Router("/reset_password", &ResetPasswordController{})
|
||||
beego.Router("/search", &SearchController{})
|
||||
|
||||
beego.Router("/login", &CommonController{}, "post:Login")
|
||||
beego.Router("/log_out", &CommonController{}, "get:LogOut")
|
||||
beego.Router("/reset", &CommonController{}, "post:ResetPassword")
|
||||
beego.Router("/userExists", &CommonController{}, "post:UserExists")
|
||||
beego.Router("/sendEmail", &CommonController{}, "get:SendEmail")
|
||||
beego.Router("/language", &CommonController{}, "get:SwitchLanguage")
|
||||
|
||||
beego.Router("/optional_menu", &OptionalMenuController{})
|
||||
beego.Router("/navigation_header", &NavigationHeaderController{})
|
||||
beego.Router("/navigation_detail", &NavigationDetailController{})
|
||||
beego.Router("/sign_in", &SignInController{})
|
||||
|
||||
//Init user Info
|
||||
//admin = &usrInfo{adminName, adminPwd}
|
||||
@ -82,68 +65,7 @@ func TestMain(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_index</title>"), "http respond should have '<title>page_title_index</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/dashboard", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/dashboard' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_dashboard</title>"), "http respond should have '<title>page_title_dashboard</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/project", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/project' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_project</title>"), "http respond should have '<title>page_title_project</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/repository", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/repository' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_repository</title>"), "http respond should have '<title>page_title_repository</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/sign_up", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/sign_up' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_sign_up</title>"), "http respond should have '<title>page_title_sign_up</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/add_new", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(401), w.Code, "'/add_new' httpStatusCode should be 401")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/account_setting", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(302), w.Code, "'/account_setting' httpStatusCode should be 302")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/change_password", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(302), w.Code, "'/change_password' httpStatusCode should be 302")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/admin_option", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(302), w.Code, "'/admin_option' httpStatusCode should be 302")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/forgot_password", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/forgot_password' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_forgot_password</title>"), "http respond should have '<title>page_title_forgot_password</title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/reset_password", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(302), w.Code, "'/reset_password' httpStatusCode should be 302")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/search", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(200), w.Code, "'/search' httpStatusCode should be 200")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>page_title_search</title>"), "http respond should have '<title>page_title_searc</title>'")
|
||||
assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title>Harbor</title>"), "http respond should have '<title>Harbor</title>'")
|
||||
|
||||
r, _ = http.NewRequest("POST", "/login", nil)
|
||||
w = httptest.NewRecorder()
|
||||
@ -171,37 +93,4 @@ func TestMain(t *testing.T) {
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(400), w.Code, "'/sendEmail' httpStatusCode should be 400")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/language", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
assert.Equal(int(302), w.Code, "'/language' httpStatusCode should be 302")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/optional_menu", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
//fmt.Printf("/optional_menu: %s\n", w.Body)
|
||||
assert.Equal(int(200), w.Code, "'/optional_menu' httpStatusCode should be 200")
|
||||
//assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title> </title>"), "http respond should have '<title> </title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/navigation_header", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
//fmt.Printf("/navigation_header: %s\n", w.Body)
|
||||
assert.Equal(int(200), w.Code, "'/navigation_header' httpStatusCode should be 200")
|
||||
//assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title> </title>"), "http respond should have '<title> </title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/navigation_detail", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
//fmt.Printf("/navigation_detail: %s\n", w.Body)
|
||||
assert.Equal(int(200), w.Code, "'/navigation_detail' httpStatusCode should be 200")
|
||||
//assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title> </title>"), "http respond should have '<title> </title>'")
|
||||
|
||||
r, _ = http.NewRequest("GET", "/sign_in", nil)
|
||||
w = httptest.NewRecorder()
|
||||
beego.BeeApp.Handlers.ServeHTTP(w, r)
|
||||
//fmt.Printf("/sign_in: %s\n", w.Body)
|
||||
assert.Equal(int(200), w.Code, "'/sign_in' httpStatusCode should be 200")
|
||||
//assert.Equal(true, strings.Contains(fmt.Sprintf("%s", w.Body), "<title> </title>"), "http respond should have '<title> </title>'")
|
||||
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package controllers
|
||||
|
||||
// DashboardController handles requests to /dashboard
|
||||
type DashboardController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders the dashboard page
|
||||
func (dc *DashboardController) Get() {
|
||||
dc.Forward("page_title_dashboard", "dashboard.htm")
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
package controllers
|
||||
|
||||
import "github.com/astaxie/beego"
|
||||
|
||||
// IndexController handles request to /
|
||||
type IndexController struct {
|
||||
BaseController
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// Get renders the index page
|
||||
func (ic *IndexController) Get() {
|
||||
ic.Forward("page_title_index", "index.htm")
|
||||
ic.TplExt = "html"
|
||||
ic.TplName = "index.html"
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// NavigationDetailController handles requests to /navigation_detail
|
||||
type NavigationDetailController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders user's navigation details header
|
||||
func (ndc *NavigationDetailController) Get() {
|
||||
sessionUserID := ndc.GetSession("userId")
|
||||
var isAdmin int
|
||||
if sessionUserID != nil {
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
||||
ndc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
|
||||
ndc.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
isAdmin = u.HasAdminRole
|
||||
}
|
||||
ndc.Data["IsAdmin"] = isAdmin
|
||||
ndc.TplName = "navigation-detail.htm"
|
||||
ndc.Render()
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// NavigationHeaderController handles requests to /navigation_header
|
||||
type NavigationHeaderController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders user's navigation header
|
||||
func (nhc *NavigationHeaderController) Get() {
|
||||
sessionUserID := nhc.GetSession("userId")
|
||||
var hasLoggedIn bool
|
||||
var isAdmin int
|
||||
if sessionUserID != nil {
|
||||
hasLoggedIn = true
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
||||
nhc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
|
||||
nhc.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
isAdmin = u.HasAdminRole
|
||||
}
|
||||
nhc.Data["HasLoggedIn"] = hasLoggedIn
|
||||
nhc.Data["IsAdmin"] = isAdmin
|
||||
nhc.TplName = "navigation-header.htm"
|
||||
nhc.Render()
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// OptionalMenuController handles request to /optional_menu
|
||||
type OptionalMenuController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders optional menu, Admin user has "Add User" menu
|
||||
func (omc *OptionalMenuController) Get() {
|
||||
sessionUserID := omc.GetSession("userId")
|
||||
|
||||
var hasLoggedIn bool
|
||||
var allowAddNew bool
|
||||
|
||||
var isAdminForLdap bool
|
||||
var allowSettingAccount bool
|
||||
|
||||
if sessionUserID != nil {
|
||||
hasLoggedIn = true
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
||||
omc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
|
||||
omc.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
omc.Data["Username"] = u.Username
|
||||
|
||||
if userID == 1 {
|
||||
isAdminForLdap = true
|
||||
}
|
||||
|
||||
if omc.AuthMode == "db_auth" || isAdminForLdap {
|
||||
allowSettingAccount = true
|
||||
}
|
||||
|
||||
isAdmin, err := dao.IsAdminRole(sessionUserID.(int))
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in IsAdminRole: %v", err)
|
||||
omc.CustomAbort(http.StatusInternalServerError, "")
|
||||
}
|
||||
|
||||
if isAdmin && omc.AuthMode == "db_auth" {
|
||||
allowAddNew = true
|
||||
}
|
||||
}
|
||||
omc.Data["AddNew"] = allowAddNew
|
||||
omc.Data["SettingAccount"] = allowSettingAccount
|
||||
omc.Data["HasLoggedIn"] = hasLoggedIn
|
||||
omc.TplName = "optional-menu.htm"
|
||||
omc.Render()
|
||||
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"text/template"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
email_util "github.com/vmware/harbor/src/common/utils/email"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
type messageDetail struct {
|
||||
Hint string
|
||||
URL string
|
||||
UUID string
|
||||
}
|
||||
|
||||
// SendEmail verifies the Email address and contact SMTP server to send reset password Email.
|
||||
func (cc *CommonController) SendEmail() {
|
||||
|
||||
email := cc.GetString("email")
|
||||
|
||||
pass, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`, email)
|
||||
|
||||
if !pass {
|
||||
cc.CustomAbort(http.StatusBadRequest, "email_content_illegal")
|
||||
} else {
|
||||
|
||||
queryUser := models.User{Email: email}
|
||||
exist, err := dao.UserExists(queryUser, "email")
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in UserExists: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if !exist {
|
||||
cc.CustomAbort(http.StatusNotFound, "email_does_not_exist")
|
||||
}
|
||||
|
||||
messageTemplate, err := template.ParseFiles("views/reset-password-mail.tpl")
|
||||
if err != nil {
|
||||
log.Errorf("Parse email template file failed: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
message := new(bytes.Buffer)
|
||||
|
||||
harborURL, err := config.ExtEndpoint()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get domain name: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
if harborURL == "" {
|
||||
harborURL = "localhost"
|
||||
}
|
||||
uuid := utils.GenerateRandomString()
|
||||
err = messageTemplate.Execute(message, messageDetail{
|
||||
Hint: cc.Tr("reset_email_hint"),
|
||||
URL: harborURL,
|
||||
UUID: uuid,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Message template error: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
emailSettings, err := config.Email()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get email configurations: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
mail := email_util.Mail{
|
||||
From: emailSettings.From,
|
||||
To: []string{email},
|
||||
Subject: cc.Tr("reset_email_subject"),
|
||||
Message: message.String()}
|
||||
|
||||
err = mail.SendMail()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Send email failed: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "send_email_failed")
|
||||
}
|
||||
|
||||
user := models.User{ResetUUID: uuid, Email: email}
|
||||
dao.UpdateUserResetUUID(user)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ForgotPasswordController handles requests to /forgot_password
|
||||
type ForgotPasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders forgot password page
|
||||
func (fpc *ForgotPasswordController) Get() {
|
||||
fpc.Forward("page_title_forgot_password", "forgot-password.htm")
|
||||
}
|
||||
|
||||
// ResetPasswordController handles request to /resetPassword
|
||||
type ResetPasswordController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get checks if reset_uuid in the reset link is valid and render the result page for user to reset password.
|
||||
func (rpc *ResetPasswordController) Get() {
|
||||
|
||||
resetUUID := rpc.GetString("reset_uuid")
|
||||
if resetUUID == "" {
|
||||
log.Error("Reset uuid is blank.")
|
||||
rpc.Redirect("/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
queryUser := models.User{ResetUUID: resetUUID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser: %v", err)
|
||||
rpc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
rpc.Data["ResetUuid"] = user.ResetUUID
|
||||
rpc.Forward("page_title_reset_password", "reset-password.htm")
|
||||
} else {
|
||||
rpc.Redirect("/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
// ResetPassword handles request from the reset page and reset password
|
||||
func (cc *CommonController) ResetPassword() {
|
||||
|
||||
resetUUID := cc.GetString("reset_uuid")
|
||||
if resetUUID == "" {
|
||||
cc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
|
||||
}
|
||||
|
||||
queryUser := models.User{ResetUUID: resetUUID}
|
||||
user, err := dao.GetUser(queryUser)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if user == nil {
|
||||
log.Error("User does not exist")
|
||||
cc.CustomAbort(http.StatusBadRequest, "User does not exist")
|
||||
}
|
||||
|
||||
password := cc.GetString("password")
|
||||
|
||||
if password != "" {
|
||||
user.Password = password
|
||||
err = dao.ResetUserPassword(*user)
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in ResetUserPassword: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
} else {
|
||||
cc.CustomAbort(http.StatusBadRequest, "password_is_required")
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// ProjectController handles requests to /project
|
||||
type ProjectController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders project page
|
||||
func (pc *ProjectController) Get() {
|
||||
var err error
|
||||
isSysAdmin := false
|
||||
uid := pc.GetSession("userId")
|
||||
if uid != nil {
|
||||
isSysAdmin, err = dao.IsAdminRole(uid)
|
||||
if err != nil {
|
||||
log.Warningf("Error in checking Admin Role for user, id: %d, error: %v", uid, err)
|
||||
isSysAdmin = false
|
||||
}
|
||||
}
|
||||
onlyAdmin, err := config.OnlyAdminCreateProject()
|
||||
if err != nil {
|
||||
log.Errorf("failed to determine whether only admin can create projects: %v", err)
|
||||
pc.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
pc.Data["CanCreate"] = !onlyAdmin || isSysAdmin
|
||||
pc.Forward("page_title_project", "project.htm")
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// RepositoryController handles request to /repository
|
||||
type RepositoryController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders repository page
|
||||
func (rc *RepositoryController) Get() {
|
||||
url, err := config.ExtEndpoint()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get domain name: %v", err)
|
||||
rc.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
}
|
||||
rc.Data["HarborRegUrl"] = strings.Split(url, "://")[1]
|
||||
rc.Forward("page_title_repository", "repository.htm")
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package controllers
|
||||
|
||||
// SearchController handles request to /search
|
||||
type SearchController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get rendlers search bar
|
||||
func (sc *SearchController) Get() {
|
||||
sc.Forward("page_title_search", "search.htm")
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// SignInController handles requests to /sign_in
|
||||
type SignInController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
//Get renders sign_in page
|
||||
func (sic *SignInController) Get() {
|
||||
sessionUserID := sic.GetSession("userId")
|
||||
var hasLoggedIn bool
|
||||
var username string
|
||||
if sessionUserID != nil {
|
||||
hasLoggedIn = true
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
||||
sic.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
|
||||
sic.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
username = u.Username
|
||||
}
|
||||
sic.Data["AuthMode"] = sic.AuthMode
|
||||
sic.Data["Username"] = username
|
||||
sic.Data["HasLoggedIn"] = hasLoggedIn
|
||||
sic.TplName = "sign-in.htm"
|
||||
sic.Render()
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// SignUpController handles requests to /sign_up
|
||||
type SignUpController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Get renders sign up page
|
||||
func (suc *SignUpController) Get() {
|
||||
if suc.AuthMode != "db_auth" || !suc.SelfRegistration {
|
||||
suc.CustomAbort(http.StatusForbidden, "")
|
||||
}
|
||||
suc.Data["AddNew"] = false
|
||||
suc.Forward("page_title_sign_up", "sign-up.htm")
|
||||
}
|
@ -26,39 +26,38 @@ import (
|
||||
|
||||
func initRouters() {
|
||||
|
||||
beego.SetStaticPath("static/resources", "static/resources")
|
||||
beego.SetStaticPath("static/vendors", "static/vendors")
|
||||
beego.SetStaticPath("/ng", "./static/new-ui")
|
||||
beego.SetStaticPath("/ng/harbor", "./static/new-ui")
|
||||
beego.SetStaticPath("/ng/harbor/dashboard", "./static/new-ui")
|
||||
beego.SetStaticPath("/ng/harbor/projects", "./static/new-ui")
|
||||
beego.SetStaticPath("/ng/harbor/users", "./static/new-ui")
|
||||
beego.SetStaticPath("/static", "./static")
|
||||
beego.SetStaticPath("/i18n", "./static/i18n")
|
||||
|
||||
//Page Controllers:
|
||||
beego.Router("/", &controllers.IndexController{})
|
||||
beego.Router("/dashboard", &controllers.DashboardController{})
|
||||
beego.Router("/project", &controllers.ProjectController{})
|
||||
beego.Router("/repository", &controllers.RepositoryController{})
|
||||
beego.Router("/sign_up", &controllers.SignUpController{})
|
||||
beego.Router("/add_new", &controllers.AddNewController{})
|
||||
beego.Router("/account_setting", &controllers.AccountSettingController{})
|
||||
beego.Router("/change_password", &controllers.ChangePasswordController{})
|
||||
beego.Router("/admin_option", &controllers.AdminOptionController{})
|
||||
beego.Router("/forgot_password", &controllers.ForgotPasswordController{})
|
||||
beego.Router("/reset_password", &controllers.ResetPasswordController{})
|
||||
beego.Router("/search", &controllers.SearchController{})
|
||||
beego.Router("/sign-in", &controllers.IndexController{})
|
||||
beego.Router("/sign-up", &controllers.IndexController{})
|
||||
beego.Router("/password-reset", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/harbor", &controllers.IndexController{})
|
||||
beego.Router("/harbor/sign-in", &controllers.IndexController{})
|
||||
beego.Router("/harbor/sign-up", &controllers.IndexController{})
|
||||
beego.Router("/harbor/dashboard", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/repository", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/replication", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/member", &controllers.IndexController{})
|
||||
beego.Router("/harbor/projects/:id/log", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/harbor/users", &controllers.IndexController{})
|
||||
beego.Router("/harbor/logs", &controllers.IndexController{})
|
||||
beego.Router("/harbor/replications", &controllers.IndexController{})
|
||||
beego.Router("/harbor/replications/endpoints", &controllers.IndexController{})
|
||||
beego.Router("/harbor/replications/rules", &controllers.IndexController{})
|
||||
beego.Router("/harbor/tags", &controllers.IndexController{})
|
||||
beego.Router("/harbor/configs", &controllers.IndexController{})
|
||||
|
||||
beego.Router("/login", &controllers.CommonController{}, "post:Login")
|
||||
beego.Router("/log_out", &controllers.CommonController{}, "get:LogOut")
|
||||
beego.Router("/reset", &controllers.CommonController{}, "post:ResetPassword")
|
||||
beego.Router("/userExists", &controllers.CommonController{}, "post:UserExists")
|
||||
beego.Router("/sendEmail", &controllers.CommonController{}, "get:SendEmail")
|
||||
beego.Router("/language", &controllers.CommonController{}, "get:SwitchLanguage")
|
||||
|
||||
beego.Router("/optional_menu", &controllers.OptionalMenuController{})
|
||||
beego.Router("/navigation_header", &controllers.NavigationHeaderController{})
|
||||
beego.Router("/navigation_detail", &controllers.NavigationDetailController{})
|
||||
beego.Router("/sign_in", &controllers.SignInController{})
|
||||
|
||||
//API:
|
||||
beego.Router("/api/search", &api.SearchAPI{})
|
||||
|
BIN
src/ui/static/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
@ -1,15 +0,0 @@
|
||||
reset_email_hint = Please click this link to reset your password
|
||||
reset_email_subject = Reset your password of Harbor account
|
||||
|
||||
page_title_index = Harbor
|
||||
page_title_dashboard = Dashboard - Harbor
|
||||
page_title_account_setting = Account Settings - Harbor
|
||||
page_title_reset_password = Reset Password - Harbor
|
||||
page_title_change_password = Change Password - Harbor
|
||||
page_title_forgot_password = Forgot Password - Harbor
|
||||
page_title_project = Project - Harbor
|
||||
page_title_repository = Project Details - Harbor
|
||||
page_title_search = Search - Harbor
|
||||
page_title_sign_up = Sign Up - Harbor
|
||||
page_title_add_new = Add New User - Harbor
|
||||
page_title_admin_option = Admin Options - Harbor
|
@ -1,15 +0,0 @@
|
||||
reset_email_hint = 请点击下面的链接进行重置密码操作
|
||||
reset_email_subject = 重置您的 Harbor 密码
|
||||
|
||||
page_title_index = Harbor
|
||||
page_title_dashboard = 控制面板 - Harbor
|
||||
page_title_account_setting = 账户设置 - Harbor
|
||||
page_title_reset_password = 重置密码 - Harbor
|
||||
page_title_change_password = 修改密码 - Harbor
|
||||
page_title_forgot_password = 忘记密码 - Harbor
|
||||
page_title_project = 项目 - Harbor
|
||||
page_title_repository = 项目明细 - Harbor
|
||||
page_title_search = 搜索 - Harbor
|
||||
page_title_sign_up = 注册 - Harbor
|
||||
page_title_add_new = 增加用户 - Harbor
|
||||
page_title_admin_option = 管理员选项 - Harbor
|
BIN
src/ui/static/images/harbor-logo.png
Normal file
After Width: | Height: | Size: 42 KiB |
@ -1,14 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.switch-pane-admin-options {
|
||||
display: inline;
|
||||
width: 340px;
|
||||
float: right;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.switch-pane-admin-options a, .switch-pane-admin-options span {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.switch-pane-admin-options li .active {
|
||||
border-bottom: 2px solid rgb(0, 84, 190);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.inline-help-config {
|
||||
padding: 6px;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.up-section .up-table-pane {
|
||||
overflow-y: auto;
|
||||
height: 220px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
.up-section .dl-horizontal dt{
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.up-section .dl-horizontal dt {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.create-destination {
|
||||
height: 275px;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.footer-absolute {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.footer-static {
|
||||
position: static;
|
||||
|
||||
}
|
||||
|
||||
.footer{
|
||||
width: 100%;
|
||||
clear: both;
|
||||
background-color: #A8A8A8;
|
||||
height: 44px;
|
||||
z-index: 10;
|
||||
}
|
||||
.footer p {
|
||||
padding-top: 8px;
|
||||
color: #FFFFFF;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 385px;
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.navbar-custom {
|
||||
background-image: none;
|
||||
background-color: #057ac9;
|
||||
height: 66px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
nav .container {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
nav .container-custom {
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
||||
.navbar-custom .navbar-nav > li > a,
|
||||
.navbar-custom .navbar-nav > li > a:hover,
|
||||
.navbar-custom .navbar-nav > li > a:focus,
|
||||
.navbar-custom .navbar-nav > li > a:active {
|
||||
color: white; /*Change active text color here*/
|
||||
}
|
||||
|
||||
.navbar-brand > img {
|
||||
margin-top: -25px;
|
||||
}
|
||||
|
||||
.navbar-form {
|
||||
margin-top: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
background: url("/static/resources/img/magnitude-glass.jpg") no-repeat 97% 6px;
|
||||
background-size: 1.5em;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.nav-custom li {
|
||||
float: left;
|
||||
padding: 10px 0 0 0;
|
||||
margin-right: 12px;
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.nav-custom li a {
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-custom .active {
|
||||
border-bottom: 3px solid #EFEFEF;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.dropdown .btn-link:hover,
|
||||
.dropdown .btn-link:visited,
|
||||
.dropdown .btn-link:link {
|
||||
display:inline-block;
|
||||
text-decoration: none;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dropdown-submenu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-submenu>.dropdown-menu {
|
||||
top: 0;
|
||||
left: 100%;
|
||||
margin-top: -6px;
|
||||
margin-left: -1px;
|
||||
-webkit-border-radius: 0 6px 6px 6px;
|
||||
-moz-border-radius: 0 6px 6px;
|
||||
border-radius: 0 6px 6px 6px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover>.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-submenu>a:after {
|
||||
display: block;
|
||||
content: " ";
|
||||
float: right;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-left-color: #ccc;
|
||||
margin-top: 5px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover>a:after {
|
||||
border-left-color: #fff;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left>.dropdown-menu {
|
||||
left: -100%;
|
||||
margin-left: 10px;
|
||||
-webkit-border-radius: 6px 0 6px 6px;
|
||||
-moz-border-radius: 6px 0 6px 6px;
|
||||
border-radius: 6px 0 6px 6px;
|
||||
}
|
||||
|
||||
.loading-progress {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
background-image: url('/static/resources/img/loading.gif');
|
||||
background-position: center;
|
||||
background-size: 107px;
|
||||
width: 1em;
|
||||
height: 1.2em;
|
||||
margin-bottom: 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
a:hover, a:visited, a:link {
|
||||
text-decoration: none;
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.has-logged-in {
|
||||
position: relative;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
.has-logged-in h4 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
line-height: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.has-logged-in .last-logged-in-time {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.has-logged-in .control-button {
|
||||
height: 2em;
|
||||
width: 100%;
|
||||
padding-right: 10%;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.container-fluid-custom {
|
||||
background-color: #EFEFEF;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 1px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.up-section {
|
||||
position: relative;
|
||||
padding: 15px 15px 15px;
|
||||
margin: 20px 0 0 -15px;
|
||||
background-color: #FFFFFF;
|
||||
height: 277px;
|
||||
}
|
||||
|
||||
.up-section h4 label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.right-part {
|
||||
padding-right: 0;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
margin-top: 10px;
|
||||
display: inline-block;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
box-shadow: none;
|
||||
width: 30%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.down-section {
|
||||
position: relative;
|
||||
padding: 15px 15px 15px;
|
||||
margin: 20px -15px 0 -15px;
|
||||
background-color: #FFFFFF;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.down-section-left {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.down-section ul {
|
||||
padding: 0;
|
||||
margin-left: 30px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.long-line {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.long-line-margin-right {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.down-table-pane {
|
||||
overflow-y: auto;
|
||||
height: 260px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
padding-bottom: 10px;
|
||||
margin: 10px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.underlined {
|
||||
border-bottom: 2px solid #EFEFEF;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.display-inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.title-color {
|
||||
color: #057ac9;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
margin: 0 20px 0 20px;
|
||||
text-align: left;
|
||||
overflow-y: hidden;
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.container-custom {
|
||||
position: relative;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.extend-height {
|
||||
height: 100%;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 15px;
|
||||
margin-top: 20px;
|
||||
background-color: #FFFFFF;
|
||||
height: 100%;
|
||||
min-height: 672px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-pane {
|
||||
margin: 0 10px 0 10px;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
|
||||
.table>tbody>tr>td, .table>tbody>tr>th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table-head-container {
|
||||
|
||||
}
|
||||
|
||||
.table-body-container {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
margin: 0 1em 0 1em;
|
||||
}
|
||||
|
||||
.project-pane {
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
|
||||
.pane {
|
||||
height: auto;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
min-height: 1px;
|
||||
max-height: 1px;
|
||||
}
|
||||
|
||||
.sub-pane {
|
||||
min-height: 380px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.well-custom {
|
||||
width: 100%;
|
||||
background-color: #f5f5f5;
|
||||
background-image: none;
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.form-custom {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.create-policy {
|
||||
height: 565px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form-group-custom {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.h4-custom {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.h4-custom-down {
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.hr-line {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-control-custom {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.pane-split {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#upon-pane {
|
||||
margin-top: 10px;
|
||||
height: 320px;
|
||||
}
|
||||
|
||||
#upon-pane table>tbody>tr {
|
||||
cursor: all-scroll;
|
||||
}
|
||||
#down-pane {
|
||||
height: 582px;
|
||||
}
|
||||
|
||||
.sub-pane-split {
|
||||
margin: 15px;
|
||||
height: auto;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.well-split {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.split-handle {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
cursor: ns-resize;
|
||||
color: #C0C0C0;
|
||||
}
|
||||
|
||||
.color-success {
|
||||
color: #5cb85c;
|
||||
}
|
||||
|
||||
.color-danger {
|
||||
color: #d9534f
|
||||
}
|
||||
|
||||
.color-warning {
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
.label-custom {
|
||||
margin: 0 5px 0 10px;
|
||||
}
|
||||
|
||||
.dialog-message {
|
||||
padding: 15px;
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.panel {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.pane-container {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pane-container .list-group-item {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.item-line {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.switch-pane {
|
||||
padding: 10px 15px 0 15px;
|
||||
margin: 0 10px 10px 10px;
|
||||
height: 3em;
|
||||
background-color: rgb(231,244,254);
|
||||
}
|
||||
|
||||
.switch-pane-projects {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.switch-pane-tabs {
|
||||
width: 265px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.switch-pane-tabs a,.switch-pane-tabs span {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.switch-pane-tabs li .active {
|
||||
border-bottom: 2px solid rgb(0, 84, 190);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.switch-pane-drop-down {
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin: -10px 0 0 10px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.search-projects {
|
||||
padding: 15px 10px 10px;
|
||||
}
|
||||
|
||||
.project-list {
|
||||
height: 440px;
|
||||
}
|
||||
|
||||
.project-selected {
|
||||
margin-left: -1.2em;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
text-align: left;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
.panel-group {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.repository-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.repository-table th, .repository-table td {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.each-tab-pane {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.datetime-picker-title {
|
||||
float: left;
|
||||
line-height: 2.5em;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
.input-group .form-control {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.well {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.popover{
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.popover-header {
|
||||
padding:8px 14px;
|
||||
background-color:#f7f7f7;
|
||||
border-bottom:1px solid #ebebeb;
|
||||
-webkit-border-radius:5px 5px 0 0;
|
||||
-moz-border-radius:5px 5px 0 0;
|
||||
border-radius:5px 5px 0 0;
|
||||
}
|
||||
|
||||
.popover-title {
|
||||
height: 2.5em;
|
||||
padding: 8px 14px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
||||
.alert-custom {
|
||||
position: relative;
|
||||
bottom: 42px;
|
||||
z-index: 99;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 10px;
|
||||
background-color: #f2dede;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.alert-custom .close {
|
||||
right: 0;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.search-result {
|
||||
min-height: 200px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.search-result li {
|
||||
margin-bottom: 15px;
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
.main-title {
|
||||
margin-top: 20px;
|
||||
margin-left: 180px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
width: 60%;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.form-horizontal .control-label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.form-horizontal .form-group {
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.small-size-fonts {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.asterisk {
|
||||
display: inline-block;
|
||||
margin-left: -25px;
|
||||
padding-top: 8px;
|
||||
color: red;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.css-form input.ng-invalid.ng-touched {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
width: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 160 KiB |
@ -1,35 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div id="retrievePane" class="switch-pane-drop-down" ng-show="vm.isOpen">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="form-inline search-projects">
|
||||
<div class="input-group">
|
||||
<input type="text" id="retrieveFilter" class="form-control search-icon" placeholder="" ng-model="vm.filterInput" size="30">
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="page-header">//vm.projectType | tr//: <span class="badge">//vm.resultCount//</span></h5>
|
||||
<div class="project-list pane-container">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" ng-repeat="item in vm.projects | name: vm.filterInput: 'name'" ng-click="vm.selectItem(item)">
|
||||
<span ng-show="item.project_id === vm.selectedId" class="glyphicon glyphicon-ok project-selected"></span> <a href="#/repositories?project_id=//item.project_id//">//item.name//</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,214 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.details')
|
||||
.directive('retrieveProjects', retrieveProjects);
|
||||
|
||||
RetrieveProjectsController.$inject = ['$scope', 'nameFilter', '$filter', 'trFilter', 'ListProjectService', '$location', 'getParameterByName', 'CurrentProjectMemberService', '$window'];
|
||||
|
||||
function RetrieveProjectsController($scope, nameFilter, $filter, trFilter, ListProjectService, $location, getParameterByName, CurrentProjectMemberService, $window) {
|
||||
var vm = this;
|
||||
|
||||
vm.projectName = '';
|
||||
vm.isOpen = false;
|
||||
vm.isProjectMember = false;
|
||||
vm.target = $location.path().substr(1) || 'repositories';
|
||||
vm.roleId = 0;
|
||||
|
||||
vm.isPublic = Number(getParameterByName('is_public', $location.absUrl()));
|
||||
|
||||
var DEFAULT_PAGE = 1;
|
||||
|
||||
vm.page = DEFAULT_PAGE;
|
||||
|
||||
vm.projects = [];
|
||||
vm.retrieve = retrieve;
|
||||
vm.filterInput = '';
|
||||
vm.selectItem = selectItem;
|
||||
vm.checkProjectMember = checkProjectMember;
|
||||
|
||||
function retrieve() {
|
||||
ListProjectService(vm.projectName, vm.isPublic, vm.page)
|
||||
.then(getProjectSuccess, getProjectFailed);
|
||||
}
|
||||
|
||||
$scope.$watch('vm.page', function(current) {
|
||||
if(current) {
|
||||
vm.retrieve();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.isPublic', function(current) {
|
||||
vm.projectType = vm.isPublic === 0 ? 'my_project_count' : 'public_project_count';
|
||||
});
|
||||
|
||||
$scope.$watch('vm.selectedProject', function(current) {
|
||||
if(current) {
|
||||
vm.selectedId = current.project_id;
|
||||
}
|
||||
});
|
||||
|
||||
function parseNextLink(link) {
|
||||
if(link === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parts = link.split(",");
|
||||
for(var i in parts) {
|
||||
var groups = /^\<(.*)\>;\srel=\"(\w+)\"$/.exec($.trim(parts[i]));
|
||||
if(groups && groups.length > 2){
|
||||
var url = groups[1];
|
||||
var rel = groups[2];
|
||||
if(rel === 'next') {
|
||||
return {
|
||||
'page': getParameterByName('page', url),
|
||||
'rel' : rel
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getProjectSuccess(response) {
|
||||
var partialProjects = response.data || [];
|
||||
for(var i in partialProjects) {
|
||||
vm.projects.push(partialProjects[i]);
|
||||
}
|
||||
|
||||
var nextLink = parseNextLink(response.headers("Link") || '');
|
||||
|
||||
if(nextLink) {
|
||||
vm.page = parseInt(nextLink.page);
|
||||
} else {
|
||||
|
||||
if(vm.projects.length == 0 && vm.isPublic === 0){
|
||||
$window.location.href = '/project';
|
||||
}
|
||||
|
||||
if(getParameterByName('project_id', $location.absUrl())){
|
||||
for(var i in vm.projects) {
|
||||
var project = vm.projects[i];
|
||||
if(project['project_id'] == getParameterByName('project_id', $location.absUrl())) {
|
||||
vm.selectedProject = project;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(vm.selectedProject) {
|
||||
$location.search('project_id', vm.selectedProject.project_id);
|
||||
vm.checkProjectMember(vm.selectedProject.project_id);
|
||||
}
|
||||
|
||||
vm.resultCount = vm.projects.length;
|
||||
|
||||
$scope.$watch('vm.filterInput', function(current, origin) {
|
||||
vm.resultCount = $filter('name')(vm.projects, vm.filterInput, 'name').length;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getProjectFailed(response) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_project'));
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to list projects.');
|
||||
}
|
||||
|
||||
function selectItem(item) {
|
||||
vm.selectedProject = item;
|
||||
$location.search('project_id', vm.selectedProject.project_id);
|
||||
$scope.$emit('projectChanged', true);
|
||||
}
|
||||
|
||||
$scope.$on('$locationChangeSuccess', function(e) {
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.isOpen = false;
|
||||
vm.checkProjectMember(vm.selectedProject.project_id);
|
||||
});
|
||||
|
||||
function checkProjectMember(projectId) {
|
||||
CurrentProjectMemberService(projectId)
|
||||
.success(getCurrentProjectMemberSuccess)
|
||||
.error(getCurrentProjectMemberFailed);
|
||||
}
|
||||
|
||||
function getCurrentProjectMemberSuccess(data, status) {
|
||||
console.log('Successful get current project member:' + status);
|
||||
vm.isProjectMember = true;
|
||||
if(data && data['roles'] && data['roles'].length > 0) {
|
||||
vm.roleId = data['roles'][0]['role_id'];
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentProjectMemberFailed(data, status) {
|
||||
vm.isProjectMember = false;
|
||||
console.log('Current user has no member for the project:' + status + ', location.url:' + $location.url());
|
||||
vm.target = 'repositories';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function retrieveProjects() {
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
templateUrl: '/static/resources/js/components/details/retrieve-projects.directive.html',
|
||||
scope: {
|
||||
'target': '=',
|
||||
'isOpen': '=',
|
||||
'selectedProject': '=',
|
||||
'isPublic': '=',
|
||||
'isProjectMember': '=',
|
||||
'roleId': '='
|
||||
},
|
||||
link: link,
|
||||
controller: RetrieveProjectsController,
|
||||
bindToController: true,
|
||||
controllerAs: 'vm'
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
$(document).on('click', clickHandler);
|
||||
|
||||
function clickHandler(e) {
|
||||
$('[data-toggle="popover"],[data-original-title]').each(function () {
|
||||
if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
|
||||
(($(this).popover('hide').data('bs.popover')||{}).inState||{}).click = false;
|
||||
}
|
||||
});
|
||||
var targetId = $(e.target).attr('id');
|
||||
if(targetId === 'switchPane' ||
|
||||
targetId === 'retrievePane' ||
|
||||
targetId === 'retrieveFilter') {
|
||||
return;
|
||||
}else{
|
||||
ctrl.isOpen = false;
|
||||
scope.$apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,19 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="switch-pane-projects" ng-switch="vm.isOpen">
|
||||
<a id="switchPane" href="javascript:void(0);" ng-click="vm.switchPane()" >//vm.projectName//</a>
|
||||
<span ng-switch-default class="glyphicon glyphicon-triangle-right" style="font-size: 12px;"></span>
|
||||
<span ng-switch-when="true" class="glyphicon glyphicon-triangle-bottom" style="font-size: 12px;"></span>
|
||||
</div>
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.details')
|
||||
.directive('switchPaneProjects', switchPaneProjects);
|
||||
|
||||
SwitchPaneProjectsController.$inject = ['$scope'];
|
||||
|
||||
function SwitchPaneProjectsController($scope) {
|
||||
var vm = this;
|
||||
|
||||
$scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
if(current){
|
||||
vm.projectName = current.name;
|
||||
vm.selectedProject = current;
|
||||
}
|
||||
});
|
||||
|
||||
vm.switchPane = switchPane;
|
||||
|
||||
function switchPane() {
|
||||
if(vm.isOpen) {
|
||||
vm.isOpen = false;
|
||||
}else{
|
||||
vm.isOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function switchPaneProjects() {
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
templateUrl: '/static/resources/js/components/details/switch-pane-projects.directive.html',
|
||||
scope: {
|
||||
'isOpen': '=',
|
||||
'selectedProject': '='
|
||||
},
|
||||
controller: SwitchPaneProjectsController,
|
||||
controllerAs: 'vm',
|
||||
bindToController: true
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,18 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div ng-show="toggleAlert" class="alert alert-danger alert-dismissible alert-custom" role="alert">
|
||||
<button type="button" class="close" ng-click="close()"><span aria-hidden="true">×</span></button>
|
||||
<strong>// 'caution' | tr //</strong> //message//
|
||||
</div>
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.dismissable.alerts')
|
||||
.directive('dismissableAlerts', dismissableAlerts);
|
||||
|
||||
function dismissableAlerts() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.html',
|
||||
'link': link
|
||||
};
|
||||
return directive;
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
scope.close = function() {
|
||||
scope.toggleAlert = false;
|
||||
};
|
||||
scope.$on('raiseAlert', function(e, val) {
|
||||
console.log('received raiseAlert:' + angular.toJson(val));
|
||||
if(val.show) {
|
||||
scope.message = val.message;
|
||||
scope.toggleAlert = true;
|
||||
}else{
|
||||
scope.message = '';
|
||||
scope.toggleAlert = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular.module('harbor.dismissable.alerts', []);
|
||||
|
||||
})();
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.element.height')
|
||||
.directive('elementHeight', elementHeight);
|
||||
|
||||
function elementHeight($window) {
|
||||
var directive = {
|
||||
'restrict': 'A',
|
||||
'link': link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs) {
|
||||
|
||||
var w = angular.element($window);
|
||||
|
||||
scope.getDimension = function() {
|
||||
return {'h' : w.height()};
|
||||
};
|
||||
|
||||
if(!angular.isDefined(scope.subsHeight)) {scope.subsHeight = 110;}
|
||||
if(!angular.isDefined(scope.subsSection)) {scope.subsSection = 32;}
|
||||
if(!angular.isDefined(scope.subsSubPane)) {scope.subsSubPane = 226;}
|
||||
if(!angular.isDefined(scope.subsTblBody)) {scope.subsTblBody = 40;}
|
||||
|
||||
scope.$watch(scope.getDimension, function(current) {
|
||||
if(current) {
|
||||
var h = current.h;
|
||||
element.css({'height': (h - scope.subsHeight) + 'px'});
|
||||
element.find('.section').css({'height': (h - scope.subsHeight - scope.subsSection) + 'px'});
|
||||
element.find('.sub-pane').css({'height': (h - scope.subsHeight - scope.subsSubPane) + 'px'});
|
||||
element.find('.tab-pane').css({'height': (h - scope.subsHeight - scope.subsSubPane - scope.subsSection -100) + 'px'});
|
||||
}
|
||||
}, true);
|
||||
|
||||
w.on('pageshow, resize', function() {
|
||||
scope.$apply();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.element.height', []);
|
||||
|
||||
})();
|
@ -1,3 +0,0 @@
|
||||
<a href="javascript:void(0);" role="button" tabindex="0" data-trigger="focus" data-toggle="popover" data-placement="right">
|
||||
<span class="glyphicon glyphicon-info-sign"></span>
|
||||
</a>
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.inline.help')
|
||||
.directive('inlineHelp', inlineHelp);
|
||||
function InlineHelpController() {
|
||||
var vm = this;
|
||||
}
|
||||
function inlineHelp() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/inline-help/inline-help.directive.html',
|
||||
'scope': {
|
||||
'helpTitle': '@',
|
||||
'content': '@'
|
||||
},
|
||||
'replace': true,
|
||||
'link': link,
|
||||
'controller': InlineHelpController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
function link(scope, element, attr, ctrl) {
|
||||
element.popover({
|
||||
'title': ctrl.helpTitle,
|
||||
'content': ctrl.content,
|
||||
'html': true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.inline.help', []);
|
||||
|
||||
})();
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.loading.progress')
|
||||
.directive('loadingProgress', loadingProgress);
|
||||
|
||||
function loadingProgress() {
|
||||
var directive = {
|
||||
'restrict': 'EA',
|
||||
'scope': {
|
||||
'toggleInProgress': '=',
|
||||
'hideTarget': '@'
|
||||
},
|
||||
'link': link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs) {
|
||||
var spinner = $('<span class="loading-progress">');
|
||||
|
||||
function convertToBoolean(val) {
|
||||
return val === 'true' ? true : false;
|
||||
}
|
||||
|
||||
var hideTarget = convertToBoolean(scope.hideTarget);
|
||||
|
||||
var pristine = element.html();
|
||||
|
||||
scope.$watch('toggleInProgress', function(current) {
|
||||
if(scope.toggleInProgress) {
|
||||
element.attr('disabled', 'disabled');
|
||||
if(hideTarget) {
|
||||
element.html(spinner);
|
||||
}else{
|
||||
spinner = spinner.css({'margin-left': '5px'});
|
||||
element.append(spinner);
|
||||
}
|
||||
}else{
|
||||
if(hideTarget) {
|
||||
element.html(pristine);
|
||||
}else{
|
||||
element.find('.loading-progress').remove();
|
||||
}
|
||||
element.removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.loading.progress', []);
|
||||
|
||||
})();
|
@ -1,68 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="well panel-group well-custom" style="margin-left: 0; position: absolute; width: 98%;">
|
||||
<div class="row">
|
||||
<div class="pull-right clearfix"><a href="javascript:void(0);" ng-click="vm.close()"><span class="glyphicon glyphicon-remove-circle"></span></a></div>
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<form class="form">
|
||||
<div class="form-group">
|
||||
<label for="">// 'operation' | tr //:</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" ng-model="vm.opAll" ng-checked="vm.opCreate && vm.opPull && vm.opPush && vm.opDelete && vm.opOthers" ng-click="vm.checkOperation({checked: 'all'})"> // 'all' | tr //
|
||||
<input type="checkbox" ng-checked="vm.opCreate" ng-model="vm.opCreate" ng-click="vm.checkOperation({checked: 'create'})"> Create
|
||||
<input type="checkbox" ng-checked="vm.opPull" ng-model="vm.opPull" ng-click="vm.checkOperation({checked: 'pull'})"> Pull
|
||||
<input type="checkbox" ng-checked="vm.opPush" ng-model="vm.opPush" ng-click="vm.checkOperation({checked: 'push'})"> Push
|
||||
<input type="checkbox" ng-checked="vm.opDelete" ng-model="vm.opDelete" ng-click="vm.checkOperation({checked: 'delete'})"> Delete
|
||||
<input type="checkbox" ng-checked="vm.opOthers" ng-model="vm.opOthers" ng-click="vm.checkOperation({checked: 'others'})"> // 'others' | tr //
|
||||
<input type="text" ng-model="vm.others" size="10">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="">// 'duration' | tr //:</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group inline-block col-md-5">
|
||||
<span class="datetime-picker-title">// 'from' | tr //:</span>
|
||||
<!--date-picker picked-date="vm.fromDate"></date-picker-->
|
||||
<div class="input-group datetimepicker">
|
||||
<input id="fromDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.fromDate" ng-change="vm.pickUp({key:'fromDate', value: vm.fromDate})">
|
||||
<span class="input-group-addon">
|
||||
<a href="javascript:void(0);"><span class="glyphicon glyphicon-calendar"></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group inline-block col-md-5">
|
||||
<span class="datetime-picker-title">// 'to' | tr //:</span>
|
||||
<div class="input-group datetimepicker">
|
||||
<input id="toDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.toDate" ng-change="vm.pickUp({key:'toDate', value: vm.toDate})">
|
||||
<span class="input-group-addon">
|
||||
<a href="javascript:void(0);"><span class="glyphicon glyphicon-calendar"></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<form>
|
||||
<div class="form-group" style="position: relative; top: 100px;">
|
||||
<button type="button" class="btn btn-primary" ng-click="vm.doSearch({op: vm.op})">// 'search' | tr //</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.log')
|
||||
.directive('advancedSearch', advancedSearch);
|
||||
|
||||
AdvancedSearchController.$inject = ['$scope', 'ListLogService', '$filter', 'trFilter'];
|
||||
|
||||
function AdvancedSearchController($scope, ListLogService, $filter, trFilter) {
|
||||
var vm = this;
|
||||
|
||||
vm.checkOperation = checkOperation;
|
||||
vm.close = close;
|
||||
|
||||
vm.opAll = true;
|
||||
|
||||
vm.doSearch = doSearch;
|
||||
|
||||
$scope.$watch('vm.op', function(current) {
|
||||
if(current && vm.op[0] === 'all') {
|
||||
vm.opCreate = true;
|
||||
vm.opPull = true;
|
||||
vm.opPush = true;
|
||||
vm.opDelete = true;
|
||||
vm.opOthers = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
$scope.$watch('vm.fromDate', function(current) {
|
||||
if(current) {
|
||||
vm.fromDate = current;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.toDate', function(current) {
|
||||
if(current) {
|
||||
vm.toDate = current;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
vm.opCreate = true;
|
||||
vm.opPull = true;
|
||||
vm.opPush = true;
|
||||
vm.opDelete = true;
|
||||
vm.opOthers = true;
|
||||
vm.others = '';
|
||||
|
||||
vm.op = [];
|
||||
vm.op.push('all');
|
||||
function checkOperation(e) {
|
||||
if(e.checked === 'all') {
|
||||
vm.opCreate = vm.opAll;
|
||||
vm.opPull = vm.opAll;
|
||||
vm.opPush = vm.opAll;
|
||||
vm.opDelete = vm.opAll;
|
||||
vm.opOthers = vm.opAll;
|
||||
}else {
|
||||
vm.opAll = false;
|
||||
}
|
||||
|
||||
vm.op = [];
|
||||
|
||||
if(vm.opCreate) {
|
||||
vm.op.push('create');
|
||||
}
|
||||
if(vm.opPull) {
|
||||
vm.op.push('pull');
|
||||
}
|
||||
if(vm.opPush) {
|
||||
vm.op.push('push');
|
||||
}
|
||||
if(vm.opDelete) {
|
||||
vm.op.push('delete');
|
||||
}
|
||||
if(vm.opOthers && $.trim(vm.others) !== '') {
|
||||
vm.op.push($.trim(vm.others));
|
||||
}
|
||||
}
|
||||
|
||||
vm.pickUp = pickUp;
|
||||
|
||||
function pickUp(e) {
|
||||
switch(e.key){
|
||||
case 'fromDate':
|
||||
vm.fromDate = e.value;
|
||||
break;
|
||||
case 'toDate':
|
||||
vm.toDate = e.value;
|
||||
break;
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
function close() {
|
||||
vm.op = [];
|
||||
vm.op.push('all');
|
||||
vm.fromDate = '';
|
||||
vm.toDate = '';
|
||||
vm.others = '';
|
||||
vm.isOpen = false;
|
||||
}
|
||||
|
||||
function doSearch (e){
|
||||
if(vm.opOthers && $.trim(vm.others) !== '') {
|
||||
e.op.push(vm.others);
|
||||
}
|
||||
if(vm.fromDate && vm.toDate && (getDateValue(vm.fromDate) > getDateValue(vm.toDate))) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('begin_date_is_later_than_end_date'));
|
||||
$scope.$emit('raiseError', true);
|
||||
return
|
||||
}
|
||||
vm.search(e);
|
||||
}
|
||||
|
||||
function getDateValue(date) {
|
||||
if(date) {
|
||||
return new Date(date);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function advancedSearch(I18nService) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/log/advanced-search.directive.html',
|
||||
'scope': {
|
||||
'isOpen': '=',
|
||||
'op': '=',
|
||||
'opOthers': '=',
|
||||
'others': '=',
|
||||
'fromDate': '=',
|
||||
'toDate': '=',
|
||||
'search': '&'
|
||||
},
|
||||
'link': link,
|
||||
'controller': AdvancedSearchController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
element.find('.datetimepicker').datetimepicker({
|
||||
locale: I18nService().getCurrentLanguage(),
|
||||
ignoreReadonly: true,
|
||||
format: 'L',
|
||||
showClear: true
|
||||
});
|
||||
element.find('#fromDatePicker').on('blur', function(){
|
||||
ctrl.pickUp({'key': 'fromDate', 'value': $(this).val()});
|
||||
});
|
||||
element.find('#toDatePicker').on('blur', function(){
|
||||
ctrl.pickUp({'key': 'toDate', 'value': $(this).val()});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,57 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="tab-pane" id="logs" element-height>
|
||||
<div class="col-xs-12 col-md-12 each-tab-pane">
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" id="txtSearchInput" class="form-control" placeholder="" ng-model="vm.username" size="30">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" ng-click="vm.search({op: vm.op, username: vm.username})"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-link" type="button" ng-click="vm.showAdvancedSearch()">// 'advanced_search' | tr //</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<advanced-search ng-show="vm.isOpen" is-open="vm.isOpen" op="vm.op" others="vm.others" search='vm.search({op: vm.op, username: vm.username})' from-date="vm.fromDate" to-date="vm.toDate" op-others="vm.opOthers"></advanced-search>
|
||||
<div class="pane">
|
||||
<div class="sub-pane">
|
||||
<div class="table-head-container">
|
||||
<table class="table table-pane table-header">
|
||||
<thead>
|
||||
<th width="18%">// 'username' | tr //</th>
|
||||
<th width="28%">// 'repository_name' | tr //</th>
|
||||
<th width="15%">// 'tag' | tr //</th>
|
||||
<th width="14%">// 'operation' | tr //</th>
|
||||
<th width="25%">// 'timestamp' | tr //</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-body-container">
|
||||
<table class="table table-pane">
|
||||
<tbody>
|
||||
<tr ng-repeat="log in vm.logs">
|
||||
<td width="18%">//log.username//</td><td width="28%">//log.repo_name//</td><td width="15%">//log.repo_tag//</td><td width="14%">//log.operation//</td><td width="25%">//log.op_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<paginator ng-if="vm.totalCount > 0" total-count="//vm.totalCount//" page-size="//vm.pageSize//" page="vm.page" display-count="5"></paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.log')
|
||||
.directive('listLog', listLog);
|
||||
|
||||
ListLogController.$inject = ['$scope','ListLogService', 'getParameterByName', '$location', '$filter', 'trFilter'];
|
||||
|
||||
function ListLogController($scope, ListLogService, getParameterByName, $location, $filter, trFilter) {
|
||||
|
||||
$scope.subsTabPane = 30;
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.sectionHeight = {'min-height': '579px'};
|
||||
|
||||
vm.isOpen = false;
|
||||
|
||||
vm.beginTimestamp = 0;
|
||||
vm.endTimestamp = 0;
|
||||
vm.keywords = '';
|
||||
|
||||
vm.username = $location.hash() || '';
|
||||
|
||||
vm.op = [];
|
||||
vm.opOthers = true;
|
||||
|
||||
vm.search = search;
|
||||
vm.showAdvancedSearch = showAdvancedSearch;
|
||||
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.queryParams = {
|
||||
'beginTimestamp' : vm.beginTimestamp,
|
||||
'endTimestamp' : vm.endTimestamp,
|
||||
'keywords' : vm.keywords,
|
||||
'projectId': vm.projectId,
|
||||
'username' : vm.username
|
||||
};
|
||||
|
||||
vm.page = 1;
|
||||
vm.pageSize = 15;
|
||||
|
||||
$scope.$watch('vm.page', function(current, origin) {
|
||||
if(current) {
|
||||
vm.page = current;
|
||||
retrieve(vm.queryParams, vm.page, vm.pageSize);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('retrieveData', function(e, val) {
|
||||
if(val) {
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.queryParams = {
|
||||
'beginTimestamp' : vm.beginTimestamp,
|
||||
'endTimestamp' : vm.endTimestamp,
|
||||
'keywords' : vm.keywords,
|
||||
'projectId': vm.projectId,
|
||||
'username' : vm.username
|
||||
};
|
||||
vm.username = '';
|
||||
retrieve(vm.queryParams, vm.page, vm.pageSize);
|
||||
}
|
||||
});
|
||||
|
||||
function search(e) {
|
||||
|
||||
vm.page = 1;
|
||||
|
||||
if(e.op[0] === 'all') {
|
||||
e.op = ['create', 'pull', 'push', 'delete'];
|
||||
}
|
||||
if(vm.opOthers && $.trim(vm.others) !== '') {
|
||||
e.op.push(vm.others);
|
||||
}
|
||||
|
||||
vm.queryParams.keywords = e.op.join('/');
|
||||
vm.queryParams.username = e.username;
|
||||
|
||||
vm.queryParams.beginTimestamp = toUTCSeconds(vm.fromDate, 0, 0, 0);
|
||||
vm.queryParams.endTimestamp = toUTCSeconds(vm.toDate, 23, 59, 59);
|
||||
|
||||
retrieve(vm.queryParams, vm.page, vm.pageSize);
|
||||
|
||||
}
|
||||
|
||||
function showAdvancedSearch() {
|
||||
if(vm.isOpen){
|
||||
vm.isOpen = false;
|
||||
}else{
|
||||
vm.isOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
function retrieve(queryParams, page, pageSize) {
|
||||
ListLogService(queryParams, page, pageSize)
|
||||
.then(listLogComplete)
|
||||
.catch(listLogFailed);
|
||||
}
|
||||
|
||||
function listLogComplete(response) {
|
||||
vm.logs = response.data;
|
||||
vm.totalCount = response.headers('X-Total-Count');
|
||||
|
||||
console.log('Total Count in logs:' + vm.totalCount + ', page:' + vm.page);
|
||||
|
||||
vm.isOpen = false;
|
||||
}
|
||||
function listLogFailed(response){
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_log') + response);
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to get log:' + response);
|
||||
}
|
||||
|
||||
function toUTCSeconds(date, hour, min, sec) {
|
||||
if(!angular.isDefined(date) || date === '') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var t = new Date(date);
|
||||
t.setHours(hour);
|
||||
t.setMinutes(min);
|
||||
t.setSeconds(sec);
|
||||
|
||||
return t.getTime() / 1000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
listLog.$inject = ['$timeout'];
|
||||
|
||||
function listLog($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/log/list-log.directive.html',
|
||||
'scope': {
|
||||
'sectionHeight': '='
|
||||
},
|
||||
'link': link,
|
||||
'controller': ListLogController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
element.find('#txtSearchInput').on('keydown', function(e) {
|
||||
if($(this).is(':focus') && e.keyCode === 13) {
|
||||
ctrl.search({'op': ctrl.op, 'username': ctrl.username});
|
||||
} else {
|
||||
$timeout(function() {
|
||||
if(ctrl.username.length === 0) {
|
||||
ctrl.search({'op': ctrl.op, 'username': ctrl.username});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.log');
|
||||
|
||||
|
||||
})();
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.log', [
|
||||
'harbor.services.log'
|
||||
]);
|
||||
|
||||
})();
|
@ -1,30 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">//vm.modalTitle//</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="btnOk">// 'ok' | tr //</button>
|
||||
<button type="button" ng-show="!vm.confirmOnly" class="btn btn-default" data-dismiss="modal">// 'cancel' | tr //</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.modal.dialog')
|
||||
.directive('modalDialog', modalDialog);
|
||||
|
||||
ModalDialogController.$inject = ['$scope'];
|
||||
|
||||
function ModalDialogController($scope) {
|
||||
var vm = this;
|
||||
|
||||
}
|
||||
|
||||
function modalDialog() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/modal-dialog/modal-dialog.directive.html',
|
||||
'link': link,
|
||||
'scope': {
|
||||
'contentType': '@',
|
||||
'modalTitle': '@',
|
||||
'modalMessage': '@',
|
||||
'action': '&',
|
||||
'confirmOnly': '='
|
||||
},
|
||||
'controller': ModalDialogController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
scope.$watch('contentType', function(current) {
|
||||
if(current) {
|
||||
ctrl.contentType = current;
|
||||
}
|
||||
});
|
||||
scope.$watch('confirmOnly', function(current) {
|
||||
if(current) {
|
||||
ctrl.confirmOnly = current;
|
||||
}
|
||||
});
|
||||
|
||||
scope.$watch('vm.modalMessage', function(current) {
|
||||
if(current) {
|
||||
switch(ctrl.contentType) {
|
||||
case 'text/html':
|
||||
element.find('.modal-body').html(current); break;
|
||||
case 'text/plain':
|
||||
element.find('.modal-body').text(current); break;
|
||||
default:
|
||||
element.find('.modal-body').text(current); break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on('showDialog', function(e, val) {
|
||||
if(val) {
|
||||
element.find('#myModal').modal('show');
|
||||
}else{
|
||||
element.find('#myModal').modal('hide');
|
||||
}
|
||||
});
|
||||
|
||||
element.find('#btnOk').on('click', clickHandler);
|
||||
|
||||
function clickHandler(e) {
|
||||
ctrl.action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.modal.dialog', []);
|
||||
|
||||
})();
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.optional.menu')
|
||||
.directive('optionalMenu', optionalMenu);
|
||||
|
||||
OptionalMenuController.$inject = ['$scope', '$window', 'I18nService', 'LogOutService', 'currentUser', '$timeout', 'trFilter', '$filter', 'GetVolumeInfoService'];
|
||||
|
||||
function OptionalMenuController($scope, $window, I18nService, LogOutService, currentUser, $timeoutm, trFilter, $filter, GetVolumeInfoService) {
|
||||
var vm = this;
|
||||
|
||||
var i18n = I18nService();
|
||||
i18n.setCurrentLanguage(vm.language);
|
||||
vm.languageName = i18n.getLanguageName(vm.language);
|
||||
console.log('current language:' + vm.languageName);
|
||||
|
||||
vm.supportLanguages = i18n.getSupportLanguages();
|
||||
vm.user = currentUser.get();
|
||||
vm.setLanguage = setLanguage;
|
||||
vm.logOut = logOut;
|
||||
vm.about = about;
|
||||
|
||||
function setLanguage(language) {
|
||||
vm.languageName = i18n.getLanguageName(vm.language);
|
||||
var hash = $window.location.hash;
|
||||
$window.location.href = '/language?lang=' + language + '&hash=' + encodeURIComponent(hash);
|
||||
}
|
||||
function logOut() {
|
||||
LogOutService()
|
||||
.success(logOutSuccess)
|
||||
.error(logOutFailed);
|
||||
}
|
||||
function logOutSuccess(data, status) {
|
||||
currentUser.unset();
|
||||
$window.location.href= '/';
|
||||
}
|
||||
function logOutFailed(data, status) {
|
||||
console.log('Failed to log out:' + data);
|
||||
}
|
||||
|
||||
var raiseInfo = {
|
||||
'confirmOnly': true,
|
||||
'contentType': 'text/html',
|
||||
'action': function() {}
|
||||
};
|
||||
|
||||
function about() {
|
||||
$scope.$emit('modalTitle', $filter('tr')('about_harbor'));
|
||||
vm.modalMessage = $filter('tr')('current_version', [vm.version || 'Unknown']);
|
||||
if(vm.showDownloadCert === 'true') {
|
||||
appendDownloadCertLink();
|
||||
}
|
||||
GetVolumeInfoService("data")
|
||||
.then(getVolumeInfoSuccess, getVolumeInfoFailed);
|
||||
}
|
||||
function getVolumeInfoSuccess(response) {
|
||||
var storage = response.data;
|
||||
vm.modalMessage += '<br/>' + $filter('tr')('current_storage',
|
||||
[toGigaBytes(storage['storage']['free']), toGigaBytes(storage['storage']['total'])]);
|
||||
$scope.$emit('modalMessage', vm.modalMessage);
|
||||
$scope.$emit('raiseInfo', raiseInfo);
|
||||
|
||||
}
|
||||
function getVolumeInfoFailed(response) {
|
||||
$scope.$emit('modalMessage', vm.modalMessage);
|
||||
$scope.$emit('raiseInfo', raiseInfo);
|
||||
}
|
||||
|
||||
function toGigaBytes(val) {
|
||||
return Math.round(val / (1024 * 1024 * 1024));
|
||||
}
|
||||
|
||||
function appendDownloadCertLink() {
|
||||
vm.modalMessage += '<br/>' + $filter('tr')('default_root_cert', ['/api/systeminfo/getcert', $filter('tr')('download')]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function optionalMenu() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/optional_menu?timestamp=' + new Date().getTime(),
|
||||
'scope': {
|
||||
'version': '@',
|
||||
'language': '@',
|
||||
'showDownloadCert': '@'
|
||||
},
|
||||
'controller': OptionalMenuController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.optional.menu', [
|
||||
'harbor.services.user',
|
||||
'harbor.services.i18n'
|
||||
]);
|
||||
|
||||
})();
|
@ -1,39 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<nav aria-label="Page navigation" class="pull-left">
|
||||
<ul class="pagination" style="margin: 0 0 0 10px;">
|
||||
<li ng-class="vm.disabledFirst" ng-show="vm.visible">
|
||||
<a href="javascript:void(0);" ng-click="vm.gotoFirst()" aria-label="Previous">
|
||||
<span aria-hidden="true"><<</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="vm.disabledPrevious" ng-show="vm.visible">
|
||||
<a href="javascript:void(0);" ng-click="vm.previous()" aria-label="Previous">
|
||||
<span aria-hidden="true"><</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="vm.disabledNext" ng-show="vm.visible">
|
||||
<a href="javascript:void(0);" ng-click="vm.next()" aria-label="Next">
|
||||
<span aria-hidden="true">></span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="vm.disabledLast" ng-show="vm.visible">
|
||||
<a href="javascript:void(0);" ng-click="vm.gotoLast()" aria-label="Next">
|
||||
<span aria-hidden="true">>></span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<p class="pull-right" style="margin-right: 15%; margin-top: 5px;">// 'total' | tr // // vm.totalCount // // 'items' | tr //</p>
|
@ -1,253 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.paginator')
|
||||
.directive('paginator', paginator);
|
||||
|
||||
PaginatorController.$inject = [];
|
||||
|
||||
function PaginatorController() {
|
||||
var vm = this;
|
||||
}
|
||||
|
||||
paginator.$inject = [];
|
||||
|
||||
function paginator() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/paginator/paginator.directive.html',
|
||||
'scope': {
|
||||
'totalCount': '@',
|
||||
'pageSize': '@',
|
||||
'page': '=',
|
||||
'displayCount': '@'
|
||||
},
|
||||
'link': link,
|
||||
'controller': PaginatorController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
scope.$watch('vm.page', function(current) {
|
||||
if(current) {
|
||||
ctrl.page = current;
|
||||
togglePageButton();
|
||||
}
|
||||
});
|
||||
|
||||
var tc;
|
||||
|
||||
scope.$watch('vm.totalCount', function(current) {
|
||||
if(current) {
|
||||
var totalCount = current;
|
||||
|
||||
tc = new TimeCounter();
|
||||
|
||||
console.log('Total Count:' + totalCount + ', Page Size:' + ctrl.pageSize + ', Display Count:' + ctrl.displayCount + ', Page:' + ctrl.page);
|
||||
|
||||
ctrl.buttonCount = Math.ceil(totalCount / ctrl.pageSize);
|
||||
|
||||
if(ctrl.buttonCount <= ctrl.displayCount) {
|
||||
tc.setMaximum(1);
|
||||
ctrl.visible = false;
|
||||
}else{
|
||||
tc.setMaximum(Math.ceil(ctrl.buttonCount / ctrl.displayCount));
|
||||
ctrl.visible = true;
|
||||
}
|
||||
|
||||
ctrl.gotoFirst = gotoFirst;
|
||||
ctrl.gotoLast = gotoLast;
|
||||
|
||||
if(ctrl.buttonCount < ctrl.page) {
|
||||
ctrl.page = ctrl.buttonCount;
|
||||
}
|
||||
|
||||
ctrl.previous = previous;
|
||||
ctrl.next = next;
|
||||
|
||||
drawButtons(tc.getTime());
|
||||
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
|
||||
toggleFirst();
|
||||
toggleLast();
|
||||
|
||||
togglePageButton();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
var TimeCounter = function() {
|
||||
this.time = 0;
|
||||
this.minimum = 0;
|
||||
this.maximum = 0;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.setMaximum = function(maximum) {
|
||||
this.maximum = maximum;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.getMaximum = function() {
|
||||
return this.maximum;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.increment = function() {
|
||||
if(this.time < this.maximum) {
|
||||
++this.time;
|
||||
if((ctrl.page % ctrl.displayCount) != 0) {
|
||||
ctrl.page = this.time * ctrl.displayCount;
|
||||
}
|
||||
++ctrl.page;
|
||||
}
|
||||
};
|
||||
|
||||
TimeCounter.prototype.canIncrement = function() {
|
||||
if(this.time + 1 < this.maximum) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.decrement = function() {
|
||||
if(this.time > this.minimum) {
|
||||
if(this.time === 0) {
|
||||
ctrl.page = ctrl.displayCount;
|
||||
}else{
|
||||
ctrl.page = this.time * ctrl.displayCount;
|
||||
}
|
||||
--this.time;
|
||||
}
|
||||
};
|
||||
|
||||
TimeCounter.prototype.canDecrement = function() {
|
||||
if(this.time > this.minimum) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.getTime = function() {
|
||||
return this.time;
|
||||
};
|
||||
|
||||
TimeCounter.prototype.setTime = function(time) {
|
||||
this.time = time;
|
||||
};
|
||||
|
||||
function drawButtons(time) {
|
||||
element.find('li[tag="pagination-button"]').remove();
|
||||
var buttons = [];
|
||||
for(var i = 1; i <= ctrl.displayCount; i++) {
|
||||
var displayNumber = ctrl.displayCount * time + i;
|
||||
if(displayNumber <= ctrl.buttonCount) {
|
||||
buttons.push('<li tag="pagination-button"><a href="javascript:void(0)" page="' + displayNumber + '">' + displayNumber + '<span class="sr-only"></span></a></li>');
|
||||
}
|
||||
}
|
||||
|
||||
$(buttons.join(''))
|
||||
.insertAfter(element.find('ul li:eq(' + (ctrl.visible ? 1 : 0) + ')')).end()
|
||||
.on('click', buttonClickHandler);
|
||||
}
|
||||
|
||||
function togglePrevious(status) {
|
||||
ctrl.disabledPrevious = status ? '' : 'disabled';
|
||||
toggleFirst();
|
||||
toggleLast();
|
||||
}
|
||||
|
||||
function toggleNext(status) {
|
||||
ctrl.disabledNext = status ? '' : 'disabled';
|
||||
toggleFirst();
|
||||
toggleLast();
|
||||
}
|
||||
|
||||
function toggleFirst() {
|
||||
ctrl.disabledFirst = (ctrl.page > 1) ? '' : 'disabled';
|
||||
}
|
||||
|
||||
function toggleLast() {
|
||||
ctrl.disabledLast = (ctrl.page < ctrl.buttonCount) ? '' : 'disabled';
|
||||
}
|
||||
|
||||
function buttonClickHandler(e) {
|
||||
ctrl.page = $(e.target).attr('page');
|
||||
togglePageButton();
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
|
||||
scope.$apply();
|
||||
}
|
||||
|
||||
function togglePageButton() {
|
||||
element.find('li[tag="pagination-button"]').removeClass('active');
|
||||
element.find('li[tag="pagination-button"] a[page="' + ctrl.page + '"]').parent().addClass('active');
|
||||
}
|
||||
|
||||
function previous() {
|
||||
if(tc.canDecrement()) {
|
||||
tc.decrement();
|
||||
drawButtons(tc.getTime());
|
||||
togglePageButton();
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
}
|
||||
}
|
||||
|
||||
function gotoFirst() {
|
||||
ctrl.page = 1;
|
||||
tc.setTime(0);
|
||||
drawButtons(0);
|
||||
|
||||
toggleFirst();
|
||||
toggleLast();
|
||||
|
||||
togglePageButton();
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
}
|
||||
|
||||
function next() {
|
||||
if(tc.canIncrement()) {
|
||||
tc.increment();
|
||||
drawButtons(tc.getTime());
|
||||
togglePageButton();
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
}
|
||||
}
|
||||
|
||||
function gotoLast() {
|
||||
ctrl.page = ctrl.buttonCount;
|
||||
tc.setTime(Math.ceil(ctrl.buttonCount / ctrl.displayCount) - 1);
|
||||
drawButtons(tc.getTime());
|
||||
|
||||
toggleFirst();
|
||||
toggleLast();
|
||||
|
||||
togglePageButton();
|
||||
togglePrevious(tc.canDecrement());
|
||||
toggleNext(tc.canIncrement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.paginator', []);
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="well panel-group well-custom" style="margin-top: 10px; position: absolute; width: 98%;">
|
||||
<div class="row">
|
||||
<form name="form" class="css-form form-custom" novalidate autocomplete="off">
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<div class="form-group col-md-6">
|
||||
<input type="text" class="form-control" id="addUsername" placeholder="// 'username' | tr //" ng-model="pm.username" name="uUsername" ng-model-options="{ debounce: 250 }" ng-change="vm.reset()" required>
|
||||
<div class="error-message">
|
||||
<div ng-messages="form.$submitted && form.uUsername.$error">
|
||||
<span ng-message="required">// 'username_is_required' | tr //</span>
|
||||
</div>
|
||||
<span ng-show="vm.hasError">// vm.errorMessage | tr //</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="roleIdList">// 'role' | tr //:</label>
|
||||
<inline-help help-title="//'inline_help_role_title' | tr//" content="//'inline_help_role' | tr//"></inline-help>
|
||||
<span ng-repeat="role in vm.roles">
|
||||
<input type="radio" name="role" ng-model="vm.optRole" value="//role.id//"> //role.name | tr//
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary" id="btnSave" ng-click="vm.save(pm)">// 'save' | tr //</button>
|
||||
<button type="button" class="btn btn-default" id="btnCancel" ng-click="vm.cancel(form)">// 'cancel' | tr //</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member')
|
||||
.directive('addProjectMember', addProjectMember);
|
||||
|
||||
AddProjectMemberController.$inject = ['$scope', 'roles', 'AddProjectMemberService'];
|
||||
|
||||
function AddProjectMemberController($scope, roles, AddProjectMemberService) {
|
||||
var vm = this;
|
||||
|
||||
$scope.pm = {};
|
||||
|
||||
var pm = $scope.pm;
|
||||
|
||||
vm.roles = roles();
|
||||
vm.optRole = 1;
|
||||
|
||||
vm.save = save;
|
||||
vm.cancel = cancel;
|
||||
vm.reset = reset;
|
||||
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
|
||||
function save(pm) {
|
||||
if(pm && angular.isDefined(pm.username)) {
|
||||
AddProjectMemberService(vm.projectId, vm.optRole, pm.username)
|
||||
.success(addProjectMemberComplete)
|
||||
.error(addProjectMemberFailed);
|
||||
}
|
||||
}
|
||||
|
||||
function cancel(form) {
|
||||
|
||||
form.$setPristine();
|
||||
form.$setUntouched();
|
||||
|
||||
vm.isOpen = false;
|
||||
pm.username = '';
|
||||
vm.optRole = 1;
|
||||
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
}
|
||||
|
||||
function addProjectMemberComplete(data, status, header) {
|
||||
console.log('addProjectMemberComplete: status:' + status + ', data:' + data);
|
||||
vm.reload();
|
||||
vm.isOpen = false;
|
||||
}
|
||||
|
||||
function addProjectMemberFailed(data, status, headers) {
|
||||
if(status === 403) {
|
||||
vm.hasError = true;
|
||||
vm.errorMessage = 'failed_to_add_member';
|
||||
}
|
||||
if(status === 409 && pm.username !== '') {
|
||||
vm.hasError = true;
|
||||
vm.errorMessage = 'username_already_exist';
|
||||
}
|
||||
if(status === 404) {
|
||||
vm.hasError = true;
|
||||
vm.errorMessage = 'username_does_not_exist';
|
||||
}
|
||||
console.log('addProjectMemberFailed: status:' + status + ', data:' + data);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addProjectMember.$inject = ['$timeout'];
|
||||
|
||||
function addProjectMember($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/project-member/add-project-member.directive.html',
|
||||
'scope': {
|
||||
'projectId': '@',
|
||||
'isOpen': '=',
|
||||
'reload': '&'
|
||||
},
|
||||
'link': link,
|
||||
'controller': AddProjectMemberController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
scope.form.$setPristine();
|
||||
scope.form.$setUntouched();
|
||||
scope.$watch('vm.isOpen', function(current) {
|
||||
if(current) {
|
||||
$timeout(function() {
|
||||
element.find('[name=uUsername]:input').focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,25 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<td width="30%">//vm.username//</td>
|
||||
<td width="45%"><switch-role roles="vm.roles" edit-mode="vm.editMode" user-id="vm.userId" role-name="vm.roleName"></switch-role></td>
|
||||
<td width="25%" ng-if="vm.currentRoleId == 1">
|
||||
<a ng-show="vm.userId != vm.currentUserId" href="javascript:void(0);" ng-click="vm.updateProjectMember({projectId: vm.projectId, userId: vm.userId, roleId: vm.roleId})">
|
||||
<span ng-if="!vm.editMode" class="glyphicon glyphicon-pencil" title="// 'edit' | tr //"></span><span ng-if="vm.editMode" class="glyphicon glyphicon-ok" title="// 'confirm' | tr //">
|
||||
</a>
|
||||
<a ng-show="vm.userId != vm.currentUserId" href="javascript:void(0);" ng-click="vm.cancelUpdate()" title="// 'cancel' | tr //">
|
||||
<span ng-if="vm.editMode" class="glyphicon glyphicon-remove"></span>
|
||||
</a>
|
||||
<a ng-show="vm.userId != vm.currentUserId && !vm.editMode" href="javascript:void(0);" ng-click="vm.deleteProjectMember()" title="// 'delete' | tr //"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</td>
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member')
|
||||
.directive('editProjectMember', editProjectMember);
|
||||
|
||||
EditProjectMemberController.$inject = ['$scope', 'roles', 'getRole','EditProjectMemberService', '$filter', 'trFilter'];
|
||||
|
||||
function EditProjectMemberController($scope, roles, getRole, EditProjectMemberService, $filter, trFilter) {
|
||||
var vm = this;
|
||||
|
||||
vm.roles = roles();
|
||||
vm.editMode = false;
|
||||
vm.lastRoleName = vm.roleName;
|
||||
|
||||
$scope.$watch('vm.roleName', function(current, origin) {
|
||||
if(current) {
|
||||
vm.currentRole = getRole({'key': 'roleName', 'value': current});
|
||||
vm.roleId = vm.currentRole.id;
|
||||
}
|
||||
});
|
||||
|
||||
vm.updateProjectMember = updateProjectMember;
|
||||
vm.deleteProjectMember = deleteProjectMember;
|
||||
vm.cancelUpdate = cancelUpdate;
|
||||
|
||||
function updateProjectMember(e) {
|
||||
if(vm.editMode) {
|
||||
console.log('update project member, roleId:' + e.roleId);
|
||||
EditProjectMemberService(e.projectId, e.userId, e.roleId)
|
||||
.success(editProjectMemberComplete)
|
||||
.error(editProjectMemberFailed);
|
||||
}else {
|
||||
vm.editMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
function deleteProjectMember() {
|
||||
vm.delete();
|
||||
}
|
||||
|
||||
function editProjectMemberComplete(data, status, headers) {
|
||||
console.log('edit project member complete: ' + status);
|
||||
vm.lastRoleName = vm.roleName;
|
||||
vm.editMode = false;
|
||||
vm.reload();
|
||||
}
|
||||
|
||||
function editProjectMemberFailed(e) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_change_member'));
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to edit project member:' + e);
|
||||
}
|
||||
|
||||
function cancelUpdate() {
|
||||
vm.editMode = false;
|
||||
vm.roleName = vm.lastRoleName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function editProjectMember() {
|
||||
var directive = {
|
||||
'restrict': 'A',
|
||||
'templateUrl': '/static/resources/js/components/project-member/edit-project-member.directive.html',
|
||||
'scope': {
|
||||
'username': '=',
|
||||
'userId': '=',
|
||||
'currentUserId': '=',
|
||||
'roleName': '=',
|
||||
'projectId': '=',
|
||||
'delete': '&',
|
||||
'reload': '&',
|
||||
'currentRoleId': '@'
|
||||
},
|
||||
'controller': EditProjectMemberController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -1,47 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="tab-pane" id="users">
|
||||
<div class="col-xs-12 col-md-12 each-tab-pane">
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" id="txtSearchInput" class="form-control" placeholder="" ng-model="vm.username" size="30">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" ng-click="vm.search({projectId: vm.projectId, username: vm.username})"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<button ng-if="vm.roleId == 1 && !vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addProjectMember()"><span class="glyphicon glyphicon-plus"></span>// 'add_member' | tr //</button>
|
||||
<button ng-if="vm.roleId == 1 && vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span>// 'add_member' | tr //</button>
|
||||
</div>
|
||||
<add-project-member ng-if="vm.isOpen" is-open="vm.isOpen" project-id="//vm.projectId//" reload='vm.search({projectId: vm.projectId, username: vm.username})'></add-project-member>
|
||||
<div class="search-pane">
|
||||
<div class="sub-pane">
|
||||
<div class="table-head-container">
|
||||
<table class="table table-pane table-header">
|
||||
<thead>
|
||||
<th width="30%">// 'username' | tr //</th><th width="45%">// 'role' | tr //</th><th width="25%" ng-if="vm.roleId == 1">// 'operation' | tr //</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-body-container">
|
||||
<table class="table table-pane">
|
||||
<tbody>
|
||||
<tr ng-repeat="pr in vm.projectMembers" edit-project-member username="pr.username" project-id="vm.projectId" user-id="pr.user_id" delete="vm.deleteProjectMember({projectId: vm.projectId, userId: pr.user_id})" current-user-id="vm.user.user_id" role-name="pr.role_name" reload='vm.search({projectId: vm.projectId, username: vm.username})' current-role-id="//vm.roleId//"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member')
|
||||
.directive('listProjectMember', listProjectMember);
|
||||
|
||||
ListProjectMemberController.$inject = ['$scope', 'ListProjectMemberService', 'DeleteProjectMemberService', 'getParameterByName', '$location', 'currentUser', '$filter', 'trFilter', '$window'];
|
||||
|
||||
function ListProjectMemberController($scope, ListProjectMemberService, DeleteProjectMemberService, getParameterByName, $location, currentUser, $filter, trFilter, $window) {
|
||||
|
||||
$scope.subsTabPane = 30;
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.sectionHeight = {'min-height': '579px'};
|
||||
|
||||
vm.isOpen = false;
|
||||
vm.search = search;
|
||||
vm.addProjectMember = addProjectMember;
|
||||
vm.deleteProjectMember = deleteProjectMember;
|
||||
vm.retrieve = retrieve;
|
||||
vm.username = '';
|
||||
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.retrieve();
|
||||
|
||||
$scope.$on('retrieveData', function(e, val) {
|
||||
if(val) {
|
||||
console.log('received retrieve data:' + val);
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.username = '';
|
||||
vm.retrieve();
|
||||
}
|
||||
});
|
||||
|
||||
function search(e) {
|
||||
vm.projectId = e.projectId;
|
||||
vm.username = e.username;
|
||||
retrieve();
|
||||
}
|
||||
|
||||
function addProjectMember() {
|
||||
vm.isOpen = !vm.isOpen;
|
||||
}
|
||||
|
||||
function deleteProjectMember(e) {
|
||||
DeleteProjectMemberService(e.projectId, e.userId)
|
||||
.success(deleteProjectMemberSuccess)
|
||||
.error(deleteProjectMemberFailed);
|
||||
}
|
||||
|
||||
function deleteProjectMemberSuccess(data, status) {
|
||||
console.log('Successful delete project member.');
|
||||
vm.retrieve();
|
||||
}
|
||||
|
||||
function deleteProjectMemberFailed(e) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_delete_member'));
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to edit project member:' + e);
|
||||
}
|
||||
|
||||
function retrieve() {
|
||||
ListProjectMemberService(vm.projectId, {'username': vm.username})
|
||||
.then(getProjectMemberComplete)
|
||||
.catch(getProjectMemberFailed);
|
||||
}
|
||||
|
||||
function getProjectMemberComplete(response) {
|
||||
vm.user = currentUser.get();
|
||||
vm.projectMembers = response.data || [];
|
||||
}
|
||||
|
||||
function getProjectMemberFailed(response) {
|
||||
console.log('Failed to get project members:' + response);
|
||||
vm.projectMembers = [];
|
||||
$location.url('repositories').search('project_id', vm.projectId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
listProjectMember.$inject = ['$timeout'];
|
||||
|
||||
function listProjectMember($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/project-member/list-project-member.directive.html',
|
||||
'scope': {
|
||||
'sectionHeight': '=',
|
||||
'roleId': '@'
|
||||
},
|
||||
'link': link,
|
||||
'controller': ListProjectMemberController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
element.find('#txtSearchInput').on('keydown', function(e) {
|
||||
if($(this).is(':focus') && e.keyCode === 13) {
|
||||
ctrl.retrieve();
|
||||
} else {
|
||||
$timeout(function() {
|
||||
if(ctrl.username.length === 0) {
|
||||
ctrl.retrieve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member')
|
||||
.constant('roles', roles)
|
||||
.factory('getRole', getRole);
|
||||
|
||||
function roles() {
|
||||
return [
|
||||
{'id': '1', 'name': 'project_admin', 'roleName': 'projectAdmin'},
|
||||
{'id': '2', 'name': 'developer', 'roleName': 'developer'},
|
||||
{'id': '3', 'name': 'guest', 'roleName': 'guest'}
|
||||
];
|
||||
}
|
||||
|
||||
getRole.$inject = ['roles', '$filter', 'trFilter'];
|
||||
|
||||
function getRole(roles, $filter, trFilter) {
|
||||
var r = roles();
|
||||
return get;
|
||||
function get(query) {
|
||||
|
||||
for(var i = 0; i < r.length; i++) {
|
||||
var role = r[i];
|
||||
if(query.key === 'roleName' && role.roleName === query.value || query.key === 'roleId' && role.id === String(query.value)) {
|
||||
return role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member', [
|
||||
'harbor.services.project.member',
|
||||
'harbor.services.user'
|
||||
]);
|
||||
|
||||
})();
|
@ -1,19 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<ng-switch on="vm.editMode">
|
||||
<span ng-switch-default>//vm.currentRole.name | tr//</span>
|
||||
<select class="form-control" style="width: auto; height: auto; padding: 0;" ng-switch-when="true" ng-model="vm.currentRole" ng-options="role as (role.name | tr) for role in vm.roles track by role.roleName" ng-change="vm.selectRole(vm.currentRole)">
|
||||
</select>
|
||||
</ng-switch>
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project.member')
|
||||
.directive('switchRole', switchRole);
|
||||
|
||||
SwitchRoleController.$inject = ['getRole', '$scope'];
|
||||
|
||||
function SwitchRoleController(getRole, $scope) {
|
||||
var vm = this;
|
||||
|
||||
$scope.$watch('vm.roleName', function(current,origin) {
|
||||
if(current) {
|
||||
vm.currentRole = getRole({'key': 'roleName', 'value': current});
|
||||
}
|
||||
});
|
||||
|
||||
vm.selectRole = selectRole;
|
||||
|
||||
function selectRole(role) {
|
||||
vm.currentRole = getRole({'key': 'roleName', 'value': role.roleName});
|
||||
vm.roleName = role.roleName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function switchRole() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/project-member/switch-role.directive.html',
|
||||
'scope': {
|
||||
'roles': '=',
|
||||
'editMode': '=',
|
||||
'userId': '=',
|
||||
'roleName': '='
|
||||
},
|
||||
'controller' : SwitchRoleController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="well well-custom" style="position: absolute; margin-left: 10px; margin-top: 5px; width: 94%;">
|
||||
<form name="form" class="css-form form-custom" novalidate autocomplete="off">
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<div class="form-group col-md-7">
|
||||
<input type="text" class="form-control" placeholder="// 'project_name' | tr //" ng-model="p.projectName" name="uProjectName" ng-change="vm.reset()" ng-model-options="{ debounce: 250 }" project-name required>
|
||||
<div class="error-message">
|
||||
<div ng-messages="form.$submitted && form.uProjectName.$error">
|
||||
<span ng-message="required">// 'project_name_is_required' | tr //</span>
|
||||
<span ng-message="projectName">// 'project_name_is_invalid' | tr //</span>
|
||||
</div>
|
||||
<span ng-show="vm.hasError">// vm.errorMessage | tr //</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="margin-top: 5px;">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="vm.isPublic"> // 'public' | tr //
|
||||
</label>
|
||||
<inline-help help-title="//'inline_help_publicity_title' | tr//" content="//'inline_help_publicity' | tr//"></inline-help>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary" ng-click="vm.addProject(p)">// 'save' | tr //</button>
|
||||
<button type="button" class="btn btn-default" ng-click="vm.cancel(form)">// 'cancel' | tr //</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.directive('addProject', addProject);
|
||||
|
||||
AddProjectController.$inject = ['AddProjectService', '$scope'];
|
||||
|
||||
function AddProjectController(AddProjectService, $scope) {
|
||||
var vm = this;
|
||||
|
||||
$scope.p = {};
|
||||
var vm0 = $scope.p;
|
||||
vm0.projectName = '';
|
||||
vm.isPublic = 0;
|
||||
|
||||
vm.addProject = addProject;
|
||||
vm.cancel = cancel;
|
||||
|
||||
vm.reset = reset;
|
||||
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
|
||||
$scope.$watch('vm.isOpen', function(current) {
|
||||
if(current) {
|
||||
$scope.form.$setPristine();
|
||||
$scope.form.$setUntouched();
|
||||
vm0.projectName = '';
|
||||
vm.isPublic = 0;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function addProject(p) {
|
||||
if(p && angular.isDefined(p.projectName)) {
|
||||
vm.isPublic = vm.isPublic ? 1 : 0;
|
||||
AddProjectService(p.projectName, vm.isPublic)
|
||||
.success(addProjectSuccess)
|
||||
.error(addProjectFailed);
|
||||
}
|
||||
}
|
||||
|
||||
function addProjectSuccess(data, status) {
|
||||
$scope.$emit('addedSuccess', true);
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
vm.isOpen = false;
|
||||
}
|
||||
|
||||
function addProjectFailed(data, status) {
|
||||
vm.hasError = true;
|
||||
if(status === 400 && vm0.projectName !== '' && vm0.projectName.length < 4) {
|
||||
vm.errorMessage = 'project_name_is_too_short';
|
||||
}
|
||||
if(status === 400 && vm0.projectName.length > 30) {
|
||||
vm.errorMessage = 'project_name_is_too_long';
|
||||
}
|
||||
if(status === 409 && vm0.projectName !== '') {
|
||||
vm.errorMessage = 'project_already_exist';
|
||||
}
|
||||
console.log('Failed to add project:' + status);
|
||||
}
|
||||
|
||||
function cancel(form){
|
||||
if(form) {
|
||||
form.$setPristine();
|
||||
form.$setUntouched();
|
||||
}
|
||||
vm.isOpen = false;
|
||||
vm0.projectName = '';
|
||||
vm.isPublic = 0;
|
||||
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
}
|
||||
|
||||
function reset() {
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
}
|
||||
}
|
||||
|
||||
addProject.$inject = ['$timeout'];
|
||||
|
||||
function addProject($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/project/add-project.directive.html',
|
||||
'controller': AddProjectController,
|
||||
'link': link,
|
||||
'scope' : {
|
||||
'isOpen': '='
|
||||
},
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
scope.$watch('vm.isOpen', function(current) {
|
||||
if(current) {
|
||||
$timeout(function() {
|
||||
element.find(':input[name=uProjectName]').focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project', [
|
||||
'harbor.services.project',
|
||||
'harbor.services.user'
|
||||
]);
|
||||
})();
|
@ -1,16 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<button ng-if="vm.isPublic" class="btn btn-success" ng-disabled="vm.roleId != 1" ng-click="vm.toggle()">// 'button_on' | tr //</button>
|
||||
<button ng-if="!vm.isPublic" class="btn btn-danger" ng-disabled="vm.roleId != 1" ng-click="vm.toggle()">// 'button_off' | tr //</button>
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.directive('publicityButton', publicityButton);
|
||||
|
||||
PublicityButtonController.$inject = ['$scope', 'ToggleProjectPublicityService', '$filter', 'trFilter'];
|
||||
|
||||
function PublicityButtonController($scope, ToggleProjectPublicityService, $filter, trFilter) {
|
||||
var vm = this;
|
||||
vm.toggle = toggle;
|
||||
|
||||
function toggle() {
|
||||
vm.isPublic = vm.isPublic ? 0 : 1;
|
||||
ToggleProjectPublicityService(vm.projectId, vm.isPublic)
|
||||
.success(toggleProjectPublicitySuccess)
|
||||
.error(toggleProjectPublicityFailed);
|
||||
}
|
||||
|
||||
function toggleProjectPublicitySuccess(data, status) {
|
||||
|
||||
console.log('Successful toggle project publicity.');
|
||||
}
|
||||
|
||||
function toggleProjectPublicityFailed(e, status) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
var message;
|
||||
if(status === 403) {
|
||||
message = $filter('tr')('failed_to_toggle_publicity_insuffient_permissions');
|
||||
}else{
|
||||
message = $filter('tr')('failed_to_toggle_publicity');
|
||||
}
|
||||
$scope.$emit('modalMessage', message);
|
||||
$scope.$emit('raiseError', true);
|
||||
|
||||
vm.isPublic = vm.isPublic ? 0 : 1;
|
||||
console.log('Failed to toggle project publicity:' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function publicityButton() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/project/publicity-button.directive.html',
|
||||
'scope': {
|
||||
'isPublic': '=',
|
||||
'projectId': '=',
|
||||
'roleId': '@'
|
||||
},
|
||||
'link': link,
|
||||
'controller': PublicityButtonController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attr, ctrl) {
|
||||
scope.$watch('vm.isPublic', function(current, origin) {
|
||||
if(current) {
|
||||
ctrl.isPublic = current;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,121 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="modal fade" data-backdrop="static" id="createPolicyModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<form name="form" class="form-horizontal css-form" novalidate autocomplete="off">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><span class="glyphicon glyphicon-plus"></span> //vm.modalTitle//</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="create-policy">
|
||||
<div class="col-md-12" ng-show="vm.toggleErrorMessage">
|
||||
<div class="pull-right clearfix" style="padding: 5px 10px;"><a href="javascript:void(0);" ng-click="vm.closeError()"><span class="glyphicon glyphicon-remove"></span></a></div>
|
||||
<div class="bg-danger dialog-message">
|
||||
<ul class="list-unstyled" style="color: red; margin: 0;" ng-repeat="msg in vm.errorMessages track by $index">
|
||||
<li>// msg //</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<h4>// 'general_setting' | tr //</h4>
|
||||
<hr class="hr-line"/>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="name" class="col-md-3 control-label">// 'name' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" class="form-control form-control-custom" id="name" ng-model="replication.policy.name" name="uName" required maxlength="20" ng-disabled="!vm.targetEditable">
|
||||
<div class="error-message" ng-messages="form.$submitted && form.uName.$error">
|
||||
<span ng-message="required">// 'name_is_required' | tr //</span>
|
||||
<span ng-message="maxlength">// 'name_is_too_long' | tr //</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="description" class="col-md-3 control-label">// 'description' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<textarea class="form-control form-control-custom" id="description" ng-model="replication.policy.description" name="uDescription" ng-disabled="!vm.targetEditable"></textarea>
|
||||
<div class="error-message" ng-messages="form.$submitted && form.uDescription.$error">
|
||||
<span ng-message="maxlength">// 'description_is_too_long' | tr //</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="enable" class="col-md-3 control-label">// 'enable' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<input type="checkbox" class="form-control" style="margin-top: 10px; height: auto;" ng-model="replication.policy.enabled" ng-disabled="!vm.targetEditable">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="row">
|
||||
<div class="col-md-8" style="padding-left: 0;">
|
||||
<h4 class="h4-custom">// 'destination_setting' | tr //</h4>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="hr-line"/>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="destinationName" class="col-md-3 control-label">// 'name' | tr //:</label>
|
||||
<div class="col-md-7">
|
||||
<input type="text" ng-if="vm.checkedAddTarget" class="form-control form-control-custom" style="width: 50% !important;" ng-model="replication.destination.name">
|
||||
<select ng-if="!vm.checkedAddTarget" class="form-control form-control-custom" ng-model="replication.destination.selection" ng-options="d as d.name for d in vm.destinations track by d.id" ng-change="vm.selectDestination(replication.destination.selection)" style="width: 50% !important;" ng-disabled="!vm.targetEditable"></select>
|
||||
<div class="display-inline-block" ng-show="vm.targetEditable"> <input type="checkbox" ng-model="vm.checkedAddTarget" ng-checked="vm.checkedAddTarget"> // 'add_new_destination' | tr //</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="endpoint" class="col-md-3 control-label">// 'endpoint' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" class="form-control form-control-custom" id="endpoint" ng-model="replication.destination.endpoint" name="uEndpoint" ng-value="vm.endpoint" placeholder="http://ip_address" required ng-disabled="!vm.targetEditable || !vm.checkedAddTarget">
|
||||
<div class="error-message" ng-messages="form.$submitted && form.uEndpoint.$error">
|
||||
<span ng-message="required">// 'endpoint_is_required' | tr //</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="username" class="col-md-3 control-label">// 'username' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" class="form-control" id="username" ng-model="replication.destination.username" name="uUsername" ng-value="vm.username" ng-disabled="!vm.targetEditable || !vm.checkedAddTarget">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<label for="password" class="col-md-3 control-label">// 'password' | tr //:</label>
|
||||
<div class="col-md-9">
|
||||
<input type="password" class="form-control" id="password" ng-model="replication.destination.password" name="uPassword" ng-value="vm.password" ng-disabled="!vm.targetEditable || !vm.checkedAddTarget">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-9">
|
||||
<button type="button" class="btn btn-default" ng-disabled="vm.notAvailable" ng-click="vm.pingDestination()" loading-progress hide-target="false" toggle-in-progress="vm.pingTIP">// 'test_connection' | tr //</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-md-12 form-group-custom">
|
||||
<div class="col-md-3"></div>
|
||||
<div class="col-md-9">
|
||||
<span ng-if="vm.isError" class="error-message" >// vm.pingMessage //</span>
|
||||
<span ng-if="!vm.isError">// vm.pingMessage //</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button ng-show="vm.targetEditable" type="submit" class="btn btn-primary" ng-click="form.$valid && vm.save(replication)" loading-progress hide-target="false" toggle-in-progress="vm.saveTIP">// 'ok' | tr //</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">// 'close' | tr //</button>
|
||||
</div>
|
||||
</form>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
@ -1,439 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.replication')
|
||||
.directive('createPolicy', createPolicy);
|
||||
|
||||
CreatePolicyController.$inject = ['$scope', 'ListReplicationPolicyService', 'ListDestinationService', 'CreateDestinationService', 'UpdateDestinationService', 'PingDestinationService', 'CreateReplicationPolicyService', 'UpdateReplicationPolicyService', 'ListDestinationPolicyService','$location', 'getParameterByName', '$filter', 'trFilter', '$q', '$timeout'];
|
||||
|
||||
function CreatePolicyController($scope, ListReplicationPolicyService, ListDestinationService, CreateDestinationService, UpdateDestinationService, PingDestinationService, CreateReplicationPolicyService, UpdateReplicationPolicyService, ListDestinationPolicyService, $location, getParameterByName, $filter, trFilter, $q, $timeout) {
|
||||
var vm = this;
|
||||
|
||||
//Since can not set value for textarea by using vm
|
||||
//use $scope for instead.
|
||||
$scope.replication = {};
|
||||
$scope.replication.policy = {};
|
||||
$scope.replication.destination = {};
|
||||
|
||||
var vm0 = $scope.replication.policy;
|
||||
var vm1 = $scope.replication.destination;
|
||||
|
||||
vm.selectDestination = selectDestination;
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
|
||||
$scope.$on('$locationChangeSuccess', function() {
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
});
|
||||
|
||||
vm.addNew = addNew;
|
||||
vm.edit = edit;
|
||||
vm.prepareDestination = prepareDestination;
|
||||
vm.create = create;
|
||||
vm.update = update;
|
||||
vm.pingDestination = pingDestination;
|
||||
vm.checkDestinationPolicyStatus = checkDestinationPolicyStatus;
|
||||
|
||||
vm.targetEditable = true;
|
||||
vm.checkedAddTarget = false;
|
||||
|
||||
vm.notAvailable = false;
|
||||
vm.pingAvailable = true;
|
||||
vm.pingMessage = '';
|
||||
|
||||
vm.pingTIP = false;
|
||||
vm.saveTIP = false;
|
||||
|
||||
vm.closeError = closeError;
|
||||
vm.toggleErrorMessage = false;
|
||||
vm.errorMessages = [];
|
||||
|
||||
$scope.$watch('vm.destinations', function(current) {
|
||||
if(current) {
|
||||
if(!angular.isArray(current) || current.length === 0) {
|
||||
vm.notAvailable = true;
|
||||
return;
|
||||
}
|
||||
if(!angular.isDefined(vm1.selection)) {
|
||||
vm1.selection = current[0];
|
||||
vm1.endpoint = current[0].endpoint;
|
||||
vm1.username = current[0].username;
|
||||
vm1.password = current[0].password;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.checkedAddTarget', function(current) {
|
||||
if(current) {
|
||||
vm.targetEditable = true;
|
||||
vm1.name = '';
|
||||
vm1.endpoint = '';
|
||||
vm1.username = '';
|
||||
vm1.password = '';
|
||||
vm.pingMessage = '';
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.targetId', function(current) {
|
||||
if(current) {
|
||||
vm1.selection.id = current;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('replication.destination.endpoint', function(current) {
|
||||
if(current) {
|
||||
vm.notAvailable = false;
|
||||
}else{
|
||||
vm.notAvailable = true;
|
||||
}
|
||||
});
|
||||
|
||||
function selectDestination(item) {
|
||||
vm1.selection = item;
|
||||
if(angular.isDefined(item)) {
|
||||
vm.targetId = item.id;
|
||||
vm1.endpoint = item.endpoint;
|
||||
vm1.username = item.username;
|
||||
vm1.password = item.password;
|
||||
}
|
||||
}
|
||||
|
||||
function prepareDestination() {
|
||||
ListDestinationService('')
|
||||
.success(listDestinationSuccess)
|
||||
.error(listDestinationFailed);
|
||||
}
|
||||
|
||||
function addNew() {
|
||||
vm.modalTitle = $filter('tr')('add_new_policy', []);
|
||||
|
||||
vm0.name = '';
|
||||
vm0.description = '';
|
||||
vm0.enabled = true;
|
||||
}
|
||||
|
||||
function edit(policyId) {
|
||||
console.log('Edit policy ID:' + policyId);
|
||||
vm.policyId = policyId;
|
||||
|
||||
vm.modalTitle = $filter('tr')('edit_policy', []);
|
||||
|
||||
ListReplicationPolicyService(policyId)
|
||||
.success(listReplicationPolicySuccess)
|
||||
.error(listReplicationPolicyFailed);
|
||||
}
|
||||
|
||||
function create(policy) {
|
||||
vm.policy = policy;
|
||||
saveDestination();
|
||||
}
|
||||
|
||||
function saveDestination() {
|
||||
|
||||
var target = {
|
||||
'name' : vm1.name,
|
||||
'endpoint': vm1.endpoint,
|
||||
'username': vm1.username,
|
||||
'password': vm1.password
|
||||
};
|
||||
|
||||
if(vm.checkedAddTarget){
|
||||
CreateDestinationService(target.name, target.endpoint, target.username, target.password)
|
||||
.success(createDestinationSuccess)
|
||||
.error(createDestinationFailed);
|
||||
}else{
|
||||
vm.policy.targetId = vm1.selection.id || vm.destinations[0].id;
|
||||
saveOrUpdatePolicy();
|
||||
}
|
||||
}
|
||||
|
||||
function saveOrUpdatePolicy() {
|
||||
vm.saveTIP = true;
|
||||
|
||||
switch(vm.action) {
|
||||
case 'ADD_NEW':
|
||||
CreateReplicationPolicyService(vm.policy)
|
||||
.success(createReplicationPolicySuccess)
|
||||
.error(createReplicationPolicyFailed);
|
||||
break;
|
||||
case 'EDIT':
|
||||
UpdateReplicationPolicyService(vm.policyId, vm.policy)
|
||||
.success(updateReplicationPolicySuccess)
|
||||
.error(updateReplicationPolicyFailed);
|
||||
break;
|
||||
default:
|
||||
vm.saveTIP = false;
|
||||
}
|
||||
}
|
||||
|
||||
function update(policy) {
|
||||
vm.policy = policy;
|
||||
if(vm.targetEditable) {
|
||||
vm.policy.targetId = vm1.selection.id;
|
||||
saveDestination();
|
||||
}
|
||||
}
|
||||
|
||||
function pingDestination() {
|
||||
|
||||
var target = {
|
||||
'endpoint': vm1.endpoint,
|
||||
'username': vm1.username,
|
||||
'password': vm1.password
|
||||
};
|
||||
|
||||
if(vm.checkedAddTarget) {
|
||||
target.name = vm1.name;
|
||||
}
|
||||
|
||||
vm.pingMessage = $filter('tr')('pinging_target');
|
||||
vm.pingTIP = true;
|
||||
vm.isError = false;
|
||||
|
||||
PingDestinationService(target)
|
||||
.success(pingDestinationSuccess)
|
||||
.error(pingDestinationFailed);
|
||||
}
|
||||
|
||||
function checkDestinationPolicyStatus() {
|
||||
console.log('Checking destination policy status, target_ID:' + vm.targetId);
|
||||
ListDestinationPolicyService(vm.targetId)
|
||||
.success(listDestinationPolicySuccess)
|
||||
.error(listDestinationPolicyFailed);
|
||||
}
|
||||
|
||||
function closeError() {
|
||||
vm.errorMessages = [];
|
||||
vm.toggleErrorMessage = false;
|
||||
}
|
||||
|
||||
function listDestinationSuccess(data, status) {
|
||||
vm.destinations = data || [];
|
||||
}
|
||||
function listDestinationFailed(data, status) {
|
||||
vm.errorMessages.push($filter('tr')('failed_to_get_destination'));
|
||||
console.log('Failed to get destination:' + data);
|
||||
}
|
||||
|
||||
function listDestinationPolicySuccess(data, status) {
|
||||
if(vm.action === 'EDIT') {
|
||||
console.log('Current target editable:' + vm.targetEditable + ', policy ID:' + vm.policyId);
|
||||
vm.targetEditable = true;
|
||||
for(var i in data) {
|
||||
if(data[i].enabled === 1) {
|
||||
vm.targetEditable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function listDestinationPolicyFailed(data, status) {
|
||||
vm.errorMessages.push($filter('tr')('failed_to_get_destination_policies'));
|
||||
console.log('Failed to list destination policy:' + data);
|
||||
}
|
||||
|
||||
function listReplicationPolicySuccess(data, status) {
|
||||
|
||||
var replicationPolicy = data;
|
||||
|
||||
vm.targetId = replicationPolicy.target_id;
|
||||
|
||||
vm0.name = replicationPolicy.name;
|
||||
vm0.description = replicationPolicy.description;
|
||||
vm0.enabled = (replicationPolicy.enabled === 1);
|
||||
|
||||
angular.forEach(vm.destinations, function(item) {
|
||||
if(item.id === vm.targetId) {
|
||||
vm1.endpoint = item.endpoint;
|
||||
vm1.username = item.username;
|
||||
vm1.password = item.password;
|
||||
}
|
||||
});
|
||||
|
||||
vm.checkDestinationPolicyStatus();
|
||||
}
|
||||
function listReplicationPolicyFailed(data, status) {
|
||||
vm.errorMessages.push($filter('tr')('failed_to_get_replication_policy'));
|
||||
console.log('Failed to list replication policy:' + data);
|
||||
}
|
||||
function createReplicationPolicySuccess(data, status) {
|
||||
vm.saveTIP = false;
|
||||
console.log('Successful create replication policy.');
|
||||
vm.reload();
|
||||
vm.closeDialog();
|
||||
}
|
||||
function createReplicationPolicyFailed(data, status) {
|
||||
vm.saveTIP = false;
|
||||
if(status === 409) {
|
||||
vm.errorMessages.push($filter('tr')('policy_already_exists'));
|
||||
}else{
|
||||
vm.errorMessages.push($filter('tr')('failed_to_create_replication_policy'));
|
||||
}
|
||||
console.log('Failed to create replication policy:' + data);
|
||||
}
|
||||
function updateReplicationPolicySuccess(data, status) {
|
||||
console.log('Successful update replication policy.');
|
||||
vm.reload();
|
||||
vm.saveTIP = false;
|
||||
vm.closeDialog();
|
||||
}
|
||||
function updateReplicationPolicyFailed(data, status) {
|
||||
vm.saveTIP = false;
|
||||
vm.errorMessages.push($filter('tr')('failed_to_update_replication_policy'));
|
||||
console.log('Failed to update replication policy:' + data);
|
||||
}
|
||||
function createDestinationSuccess(data, status, headers) {
|
||||
var content = headers('Location');
|
||||
vm.policy.targetId = Number(content.substr(content.lastIndexOf('/') + 1));
|
||||
console.log('Successful create destination, targetId:' + vm.policy.targetId);
|
||||
saveOrUpdatePolicy();
|
||||
}
|
||||
function createDestinationFailed(data, status) {
|
||||
vm.errorMessages.push($filter('tr')('failed_to_create_destination'));
|
||||
console.log('Failed to create destination:' + data);
|
||||
}
|
||||
function updateDestinationSuccess(data, status) {
|
||||
console.log('Successful update destination.');
|
||||
vm.policy.targetId = vm1.selection.id;
|
||||
saveOrUpdatePolicy();
|
||||
}
|
||||
function updateDestinationFailed(data, status) {
|
||||
vm.errorMessages.push($filter('tr')('failed_to_update_destination'));
|
||||
$scope.$broadcast('showDialog', true);
|
||||
console.log('Failed to update destination:' + data);
|
||||
}
|
||||
function pingDestinationSuccess(data, status) {
|
||||
vm.isError = false;
|
||||
vm.pingMessage = $filter('tr')('successful_ping_target', []);
|
||||
vm.pingTIP = false;
|
||||
}
|
||||
function pingDestinationFailed(data, status) {
|
||||
vm.isError = true;
|
||||
if(status === 404) {
|
||||
data = '';
|
||||
}
|
||||
vm.pingMessage = $filter('tr')('failed_to_ping_target', []);
|
||||
console.log("Failed to ping target:" + data);
|
||||
|
||||
vm.pingTIP = false;
|
||||
}
|
||||
}
|
||||
|
||||
function createPolicy($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/replication/create-policy.directive.html',
|
||||
'scope': {
|
||||
'policyId': '@',
|
||||
'modalTitle': '@',
|
||||
'reload': '&',
|
||||
'action': '='
|
||||
},
|
||||
'link': link,
|
||||
'controller': CreatePolicyController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attr, ctrl) {
|
||||
|
||||
element.find('#createPolicyModal').on('show.bs.modal', function() {
|
||||
scope.$apply(function() {
|
||||
scope.form.$setPristine();
|
||||
scope.form.$setUntouched();
|
||||
|
||||
scope.$watch('vm.checkedAddTarget', function(current, origin) {
|
||||
if(origin) {
|
||||
var d = scope.replication.destination;
|
||||
if(angular.isDefined(d) && angular.isDefined(d.selection)) {
|
||||
ctrl.targetId = d.selection.id;
|
||||
d.endpoint = d.selection.endpoint;
|
||||
d.username = d.selection.username;
|
||||
d.password = d.selection.password;
|
||||
ctrl.checkDestinationPolicyStatus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.$watch('vm.errorMessages', function(current) {
|
||||
if(current && current.length > 0) {
|
||||
ctrl.toggleErrorMessage = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
ctrl.checkedAddTarget = false;
|
||||
ctrl.targetEditable = true;
|
||||
|
||||
ctrl.notAvailable = false;
|
||||
|
||||
ctrl.pingMessage = '';
|
||||
ctrl.pingAvailable = true;
|
||||
|
||||
ctrl.saveTIP = false;
|
||||
ctrl.pingTIP = false;
|
||||
ctrl.toggleErrorMessage = false;
|
||||
ctrl.errorMessages = [];
|
||||
|
||||
ctrl.prepareDestination();
|
||||
|
||||
switch(ctrl.action) {
|
||||
case 'ADD_NEW':
|
||||
ctrl.addNew();
|
||||
break;
|
||||
case 'EDIT':
|
||||
ctrl.edit(ctrl.policyId);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ctrl.save = save;
|
||||
ctrl.closeDialog = closeDialog;
|
||||
|
||||
function save(form) {
|
||||
|
||||
ctrl.toggleErrorMessage = false;
|
||||
ctrl.errorMessages = [];
|
||||
|
||||
var postPayload = {
|
||||
'projectId': Number(ctrl.projectId),
|
||||
'name': form.policy.name,
|
||||
'enabled': form.policy.enabled ? 1 : 0,
|
||||
'description': form.policy.description,
|
||||
'cron_str': '',
|
||||
'start_time': ''
|
||||
};
|
||||
switch(ctrl.action) {
|
||||
case 'ADD_NEW':
|
||||
ctrl.create(postPayload);
|
||||
break;
|
||||
case 'EDIT':
|
||||
ctrl.update(postPayload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
element.find('#createPolicyModal').modal('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,155 +0,0 @@
|
||||
<!--
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<div class="tab-pane">
|
||||
<div class="col-xs-12 col-md-12 each-tab-pane">
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" id="txtSearchPolicyInput" class="form-control" placeholder="" ng-model="vm.replicationPolicyName" size="30">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" ng-click="vm.searchReplicationPolicy()"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addReplication()" data-toggle="modal" data-target="#createPolicyModal"><span class="glyphicon glyphicon-plus"></span>// 'add_new_policy' | tr //</button>
|
||||
<create-policy reload="vm.retrievePolicy()" action="vm.action" modal-title="//vm.modalTitle//" policy-id="//vm.policyId//"></create-policy>
|
||||
</div>
|
||||
<div class="pane-split" id="upon-pane" style="max-height: 760px;">
|
||||
<div class="sub-pane-split">
|
||||
<div class="table-head-container">
|
||||
<table class="table table-pane table-header">
|
||||
<thead>
|
||||
<th width="10%">// 'name' | tr //</th>
|
||||
<th width="18%">// 'description' | tr //</th>
|
||||
<th width="18%">// 'destination' | tr //</th>
|
||||
<th width="18%">// 'last_start_time' | tr //</th>
|
||||
<th width="14%">// 'activation' | tr// </th>
|
||||
<th width="10%">// 'actions' | tr //</th>
|
||||
<th width="5%"></th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-body-container" style="height: 250px;">
|
||||
<table class="table table-pane">
|
||||
<tbody>
|
||||
<tr ng-if="vm.replicationPolicies.length == 0">
|
||||
<td colspan="7" height="100%" class="empty-hint" ><h4 class="text-muted">// 'no_replication_policies_add_new' | tr //</h4></td>
|
||||
</tr>
|
||||
<tr policy_id="//r.id//" ng-if="vm.replicationPolicies.length > 0" ng-repeat="r in vm.replicationPolicies" value="//vm.last = $last//">
|
||||
<td width="10%">//r.name//</td>
|
||||
<td width="18%">//r.description//</td>
|
||||
<td width="18%">//r.target_name//</td>
|
||||
<td width="18%">//r.start_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
<td width="14%" ng-switch on="//r.enabled//">
|
||||
<span ng-switch-when="1">// 'enabled' | tr //</span>
|
||||
<span ng-switch-when="0">// 'disabled' | tr //</span>
|
||||
</td>
|
||||
<td width="10%">
|
||||
<div class="display-inline-block" ng-switch on="//r.enabled//">
|
||||
<a href="javascript:void(0);" ng-click="vm.confirmToTogglePolicy(r.id, 0, r.name)" title="// 'disable' | tr //"><span ng-switch-when="1" class="glyphicon glyphicon-stop color-danger"></span></a>
|
||||
<a href="javascript:void(0);" ng-click="vm.confirmToTogglePolicy(r.id, 1, r.name)" title="// 'enable' | tr //"><span ng-switch-when="0" class="glyphicon glyphicon-play color-success"></span></a>
|
||||
</div>
|
||||
|
||||
<a href="javascript:void(0);" data-toggle="modal" data-target="#createPolicyModal" ng-click="vm.editReplication(r.id)" title="// 'edit_policy' | tr //"><span class="glyphicon glyphicon-pencil"></span></a>
|
||||
|
||||
<a href="javascript:void(0);" ng-click="vm.confirmToDelete(r.id, r.name)" title="// 'delete_policy' | tr //"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</td>
|
||||
<td width="5%">
|
||||
<a ng-if= "r.error_job_count > 0" title = "// 'found_error_in_replication_job' | tr: [r.error_job_count] //"><span class="glyphicon glyphicon-exclamation-sign color-danger" ></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-4 col-md-12 well well-sm well-custom well-split">
|
||||
<div class="col-md-offset-10">//vm.replicationPolicies ? vm.replicationPolicies.length : 0// // 'items' | tr //</div>
|
||||
</div>
|
||||
<p class="split-handle"><span class="glyphicon glyphicon-align-justify"></span></p>
|
||||
<h4 class="h4-custom-down">// 'replication_jobs' | tr //</h4>
|
||||
<hr class="hr-line"/>
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" id="txtSearchJobInput" class="form-control" placeholder="" ng-model="vm.replicationJobName" size="20">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" ng-click="vm.searchReplicationJob()" loading-progress hide-target = "true" toggle-in-progress="vm.searchJobTIP"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="selStatus" class="control-label label-custom">// 'status' | tr //:</label>
|
||||
<div class="input-group">
|
||||
<select class="form-control" id="selStatus" ng-options="st.value for st in vm.jobStatus() track by st.key" ng-model="vm.currentStatus" ng-change="vm.searchReplicationJob()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="fromDatePicker" class="control-label label-custom">// 'from' | tr //:</label>
|
||||
<div class="input-group datetimepicker">
|
||||
<input id="fromDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.fromDate" ng-change="vm.pickUp({key:'fromDate', value: vm.fromDate})" size="10">
|
||||
<span class="input-group-addon">
|
||||
<a href="javascript:void(0);"><span class="glyphicon glyphicon-calendar"></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="toDatePicker" class="control-label label-custom">// 'to' | tr //:</label>
|
||||
<div class="input-group datetimepicker">
|
||||
<input id="toDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.toDate" ng-change="vm.pickUp({key:'toDate', value: vm.toDate})" size="10">
|
||||
<span class="input-group-addon">
|
||||
<a href="javascript:void(0);"><span class="glyphicon glyphicon-calendar"></span></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<button type="button" class="btn btn-success" ng-click="vm.refreshReplicationJob()" loading-progress hide-target = "true" toggle-in-progress="vm.refreshJobTIP" title="//'refresh' | tr//"><span class="glyphicon glyphicon-refresh"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane-split" id="down-pane" style="min-height: 142px;">
|
||||
<div class="sub-pane-split">
|
||||
<div class="table-head-container">
|
||||
<table class="table table-pane table-header">
|
||||
<thead>
|
||||
<th width="15%">// 'name' | tr //</th>
|
||||
<th width="15%">// 'operation' | tr //</th>
|
||||
<th width="24%">// 'creation_time' | tr //</th>
|
||||
<th width="24%">// 'end_time' | tr //</th>
|
||||
<th width="10%">// 'status' | tr //</th>
|
||||
<th width="12%">// 'logs' | tr //</th>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-body-container" style="height: 510px; min-height: 80px;">
|
||||
<table class="table table-pane">
|
||||
<tbody>
|
||||
<tr ng-if="vm.replicationJobs.length == 0">
|
||||
<td colspan="4" height="100%" class="empty-hint" ><h4 class="text-muted">// 'no_replication_jobs' | tr //</h4></td>
|
||||
</tr>
|
||||
<tr ng-if="vm.replicationJobs.length > 0" ng-repeat="r in vm.replicationJobs">
|
||||
<td width="15%">//r.repository//</td>
|
||||
<td width="15%">//r.operation//</td>
|
||||
<td width="24%">//r.creation_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
<td width="24%">//r.update_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
<td width="10%">//r.status//</td>
|
||||
<td width="12%">
|
||||
<a style="margin-left: 20px;" ng-show="r.status != 'canceled' && r.status != 'pending'" href="javascript:void(0);" ng-click="vm.downloadLog(r.id)" title="// 'download_log' | tr //"><span class="glyphicon glyphicon-file"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<paginator ng-if="vm.totalCount > 0" total-count="//vm.totalCount//" page-size="//vm.pageSize//" display-count="5" page="vm.page"></paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,440 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.replication')
|
||||
.directive('listReplication', listReplication)
|
||||
.factory('jobStatus', jobStatus);
|
||||
|
||||
jobStatus.inject = ['$filter', 'trFilter'];
|
||||
function jobStatus($filter, trFilter) {
|
||||
return function() {
|
||||
return [
|
||||
{'key': 'all' , 'value': $filter('tr')('all')},
|
||||
{'key': 'pending', 'value': $filter('tr')('pending')},
|
||||
{'key': 'running', 'value': $filter('tr')('running')},
|
||||
{'key': 'error' , 'value': $filter('tr')('error')},
|
||||
{'key': 'retrying', 'value': $filter('tr')('retrying')},
|
||||
{'key': 'stopped', 'value': $filter('tr')('stopped')},
|
||||
{'key': 'finished', 'value':$filter('tr')('finished')},
|
||||
{'key': 'canceled', 'value': $filter('tr')('canceled')}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
ListReplicationController.$inject = ['$scope', 'getParameterByName', '$location', 'ListReplicationPolicyService', 'ToggleReplicationPolicyService', 'DeleteReplicationPolicyService', 'ListReplicationJobService', '$window', '$filter', 'trFilter', 'jobStatus'];
|
||||
|
||||
function ListReplicationController($scope, getParameterByName, $location, ListReplicationPolicyService, ToggleReplicationPolicyService, DeleteReplicationPolicyService, ListReplicationJobService, $window, $filter, trFilter, jobStatus) {
|
||||
var vm = this;
|
||||
|
||||
vm.sectionHeight = {'min-height': '1260px'};
|
||||
|
||||
$scope.$on('retrieveData', function(e, val) {
|
||||
if(val) {
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.retrievePolicy();
|
||||
}
|
||||
});
|
||||
|
||||
vm.addReplication = addReplication;
|
||||
vm.editReplication = editReplication;
|
||||
vm.deleteReplicationPolicy = deleteReplicationPolicy;
|
||||
|
||||
vm.confirmToDelete = confirmToDelete;
|
||||
|
||||
vm.searchReplicationPolicy = searchReplicationPolicy;
|
||||
vm.searchReplicationJob = searchReplicationJob;
|
||||
vm.refreshReplicationJob = refreshReplicationJob;
|
||||
|
||||
vm.retrievePolicy = retrievePolicy;
|
||||
vm.retrieveJob = retrieveJob;
|
||||
|
||||
vm.pageSize = 20;
|
||||
vm.page = 1;
|
||||
|
||||
$scope.$watch('vm.page', function(current) {
|
||||
if(vm.lastPolicyId !== -1 && current) {
|
||||
vm.page = current;
|
||||
console.log('replication job: vm.page:' + current);
|
||||
vm.retrieveJob(vm.lastPolicyId, vm.page, vm.pageSize);
|
||||
}
|
||||
});
|
||||
|
||||
vm.confirmToTogglePolicy = confirmToTogglePolicy;
|
||||
vm.togglePolicy = togglePolicy;
|
||||
|
||||
vm.downloadLog = downloadLog;
|
||||
|
||||
vm.last = false;
|
||||
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.retrievePolicy();
|
||||
|
||||
vm.jobStatus = jobStatus;
|
||||
vm.currentStatus = vm.jobStatus()[0];
|
||||
|
||||
vm.pickUp = pickUp;
|
||||
|
||||
vm.searchJobTIP = false;
|
||||
vm.refreshJobTIP = false;
|
||||
|
||||
function searchReplicationPolicy() {
|
||||
vm.retrievePolicy();
|
||||
}
|
||||
|
||||
function searchReplicationJob() {
|
||||
if(vm.lastPolicyId !== -1) {
|
||||
vm.searchJobTIP = true;
|
||||
vm.retrieveJob(vm.lastPolicyId, vm.page, vm.pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
function refreshReplicationJob() {
|
||||
if(vm.fromDate && vm.toDate && (getDateValue(vm.fromDate) > getDateValue(vm.toDate))) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('begin_date_is_later_than_end_date'));
|
||||
$scope.$emit('raiseError', true);
|
||||
return;
|
||||
}
|
||||
if(vm.lastPolicyId !== -1) {
|
||||
vm.refreshJobTIP = true;
|
||||
vm.retrieveJob(vm.lastPolicyId, vm.page, vm.pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
function retrievePolicy() {
|
||||
ListReplicationPolicyService('', vm.projectId, vm.replicationPolicyName)
|
||||
.success(listReplicationPolicySuccess)
|
||||
.error(listReplicationPolicyFailed);
|
||||
}
|
||||
|
||||
function retrieveJob(policyId, page, pageSize) {
|
||||
var status = (vm.currentStatus.key === 'all' ? '' : vm.currentStatus.key);
|
||||
ListReplicationJobService(policyId, vm.replicationJobName, status, toUTCSeconds(vm.fromDate, 0, 0, 0), toUTCSeconds(vm.toDate, 23, 59, 59), page, pageSize)
|
||||
.then(listReplicationJobSuccess, listReplicationJobFailed);
|
||||
}
|
||||
|
||||
function listReplicationPolicySuccess(data, status) {
|
||||
vm.replicationJobs = [];
|
||||
vm.replicationPolicies = data || [];
|
||||
}
|
||||
|
||||
function listReplicationPolicyFailed(data, status) {
|
||||
console.log('Failed to list replication policy:' + data);
|
||||
}
|
||||
|
||||
function listReplicationJobSuccess(response) {
|
||||
vm.replicationJobs = response.data || [];
|
||||
vm.totalCount = response.headers('X-Total-Count');
|
||||
var alertInfo = {
|
||||
'show': false,
|
||||
'message': ''
|
||||
};
|
||||
angular.forEach(vm.replicationJobs, function(item) {
|
||||
for(var key in item) {
|
||||
var value = item[key];
|
||||
if(key === 'status' && (value === 'error' || value === 'retrying')) {
|
||||
alertInfo.show = true;
|
||||
alertInfo.message = $filter('tr')('alert_job_contains_error');
|
||||
}
|
||||
switch(key) {
|
||||
case 'operation':
|
||||
case 'status':
|
||||
item[key] = $filter('tr')(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$emit('raiseAlert', alertInfo);
|
||||
vm.searchJobTIP = false;
|
||||
vm.refreshJobTIP = false;
|
||||
}
|
||||
|
||||
function listReplicationJobFailed(response) {
|
||||
console.log('Failed to list replication job:' + response);
|
||||
vm.searchJobTIP = false;
|
||||
vm.refreshJobTIP = false;
|
||||
}
|
||||
|
||||
function addReplication() {
|
||||
vm.modalTitle = $filter('tr')('add_new_policy', []);
|
||||
vm.action = 'ADD_NEW';
|
||||
}
|
||||
|
||||
function editReplication(policyId) {
|
||||
vm.policyId = policyId;
|
||||
vm.modalTitle = $filter('tr')('edit_policy', []);
|
||||
vm.action = 'EDIT';
|
||||
|
||||
console.log('Selected policy ID:' + vm.policyId);
|
||||
}
|
||||
|
||||
function deleteReplicationPolicy() {
|
||||
DeleteReplicationPolicyService(vm.policyId)
|
||||
.success(deleteReplicationPolicySuccess)
|
||||
.error(deleteReplicationPolicyFailed);
|
||||
}
|
||||
|
||||
function deleteReplicationPolicySuccess(data, status) {
|
||||
console.log('Successful delete replication policy.');
|
||||
vm.retrievePolicy();
|
||||
}
|
||||
|
||||
function deleteReplicationPolicyFailed(data, status) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
if(status === 412) {
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_delete_replication_enabled'));
|
||||
}else{
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_delete_replication_policy'));
|
||||
}
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to delete replication policy.');
|
||||
}
|
||||
|
||||
function confirmToDelete(policyId, policyName) {
|
||||
vm.policyId = policyId;
|
||||
|
||||
$scope.$emit('modalTitle', $filter('tr')('confirm_delete_policy_title'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('confirm_delete_policy', [policyName]));
|
||||
|
||||
var emitInfo = {
|
||||
'confirmOnly': false,
|
||||
'contentType': 'text/plain',
|
||||
'action': vm.deleteReplicationPolicy
|
||||
};
|
||||
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
}
|
||||
|
||||
|
||||
function confirmToTogglePolicy(policyId, enabled, name) {
|
||||
vm.policyId = policyId;
|
||||
vm.enabled = enabled;
|
||||
|
||||
var status = $filter('tr')(vm.enabled === 1 ? 'enable':'disable');
|
||||
|
||||
var title;
|
||||
var message;
|
||||
if(enabled === 1){
|
||||
title = $filter('tr')('confirm_to_toggle_enabled_policy_title');
|
||||
message = $filter('tr')('confirm_to_toggle_enabled_policy');
|
||||
}else{
|
||||
title = $filter('tr')('confirm_to_toggle_disabled_policy_title');
|
||||
message = $filter('tr')('confirm_to_toggle_disabled_policy');
|
||||
}
|
||||
$scope.$emit('modalTitle', title);
|
||||
$scope.$emit('modalMessage', message);
|
||||
|
||||
var emitInfo = {
|
||||
'contentType': 'text/html',
|
||||
'confirmOnly': false,
|
||||
'action': vm.togglePolicy
|
||||
};
|
||||
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
}
|
||||
|
||||
function togglePolicy() {
|
||||
ToggleReplicationPolicyService(vm.policyId, vm.enabled)
|
||||
.success(toggleReplicationPolicySuccess)
|
||||
.error(toggleReplicationPolicyFailed);
|
||||
}
|
||||
|
||||
function toggleReplicationPolicySuccess(data, status) {
|
||||
console.log('Successful toggle replication policy.');
|
||||
vm.retrievePolicy();
|
||||
}
|
||||
|
||||
function toggleReplicationPolicyFailed(data, status) {
|
||||
console.log('Failed to toggle replication policy.');
|
||||
}
|
||||
|
||||
function downloadLog(policyId) {
|
||||
$window.open('/api/jobs/replication/' + policyId + '/log', '_blank');
|
||||
}
|
||||
|
||||
function pickUp(e) {
|
||||
switch(e.key){
|
||||
case 'fromDate':
|
||||
vm.fromDate = e.value;
|
||||
break;
|
||||
case 'toDate':
|
||||
vm.toDate = e.value;
|
||||
break;
|
||||
}
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
function toUTCSeconds(date, hour, min, sec) {
|
||||
if(!angular.isDefined(date) || date === '') {
|
||||
return '';
|
||||
}
|
||||
var t = new Date(date);
|
||||
t.setHours(hour);
|
||||
t.setMinutes(min);
|
||||
t.setSeconds(sec);
|
||||
return t.getTime() / 1000;
|
||||
}
|
||||
|
||||
function getDateValue(date) {
|
||||
if(date) {
|
||||
return new Date(date);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
listReplication.inject = ['$timeout', 'I18nService'];
|
||||
|
||||
function listReplication($timeout, I18nService) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/replication/list-replication.directive.html',
|
||||
'scope': {
|
||||
'sectionHeight': '='
|
||||
},
|
||||
'link': link,
|
||||
'controller': ListReplicationController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
|
||||
var uponPaneHeight = element.find('#upon-pane').height();
|
||||
var downPaneHeight = element.find('#down-pane').height();
|
||||
|
||||
var uponTableHeight = element.find('#upon-pane .table-body-container').height();
|
||||
var downTableHeight = element.find('#down-pane .table-body-container').height();
|
||||
|
||||
var handleHeight = element.find('.split-handle').height() + element.find('.split-handle').offset().top + element.find('.well').height() - 32;
|
||||
console.log('handleHeight:' + handleHeight);
|
||||
var maxDownPaneHeight = 760;
|
||||
|
||||
element.find('.split-handle').on('mousedown', mousedownHandler);
|
||||
|
||||
function mousedownHandler(e) {
|
||||
e.preventDefault();
|
||||
$(document).on('mousemove', mousemoveHandler);
|
||||
$(document).on('mouseup', mouseupHandler);
|
||||
}
|
||||
|
||||
function mousemoveHandler(e) {
|
||||
|
||||
var incrementHeight = $('.container-fluid').scrollTop() + e.pageY;
|
||||
|
||||
if(element.find('#down-pane').height() <= maxDownPaneHeight) {
|
||||
element.find('#upon-pane').css({'height' : (uponPaneHeight - (handleHeight - incrementHeight)) + 'px'});
|
||||
element.find('#down-pane').css({'height' : (downPaneHeight + (handleHeight - incrementHeight)) + 'px'});
|
||||
element.find('#upon-pane .table-body-container').css({'height': (uponTableHeight - (handleHeight - incrementHeight)) + 'px'});
|
||||
element.find('#down-pane .table-body-container').css({'height': (downTableHeight + (handleHeight - incrementHeight)) + 'px'});
|
||||
}else{
|
||||
element.find('#down-pane').css({'height' : (maxDownPaneHeight) + 'px'});
|
||||
$(document).off('mousemove');
|
||||
}
|
||||
}
|
||||
|
||||
function mouseupHandler(e) {
|
||||
$(document).off('mousedown');
|
||||
$(document).off('mousemove');
|
||||
}
|
||||
|
||||
|
||||
ctrl.lastPolicyId = -1;
|
||||
|
||||
scope.$watch('vm.replicationPolicies', function(current) {
|
||||
$timeout(function(){
|
||||
if(current) {
|
||||
if(current.length > 0) {
|
||||
element.find('#upon-pane table>tbody>tr').on('click', trClickHandler);
|
||||
element.find('#upon-pane table>tbody>tr:eq(0)').trigger('click');
|
||||
}else{
|
||||
element
|
||||
.find('#upon-pane table>tbody>tr')
|
||||
.css({'background-color': '#FFFFFF'})
|
||||
.css({'color': '#000'});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function trClickHandler(e) {
|
||||
element
|
||||
.find('#upon-pane table>tbody>tr')
|
||||
.css({'background-color': '#FFFFFF'})
|
||||
.css({'color': '#000'})
|
||||
.css({'cursor': 'default'});
|
||||
element
|
||||
.find('#upon-pane table>tbody>tr a')
|
||||
.css({'color': '#337ab7'});
|
||||
$(this)
|
||||
.css({'background-color': '#057ac9'})
|
||||
.css({'color': '#fff'});
|
||||
$('a', this)
|
||||
.css({'color': '#fff'});
|
||||
ctrl.retrieveJob($(this).attr('policy_id'), ctrl.page, ctrl.pageSize);
|
||||
ctrl.lastPolicyId = $(this).attr('policy_id');
|
||||
}
|
||||
|
||||
element.find('.datetimepicker').datetimepicker({
|
||||
locale: I18nService().getCurrentLanguage(),
|
||||
ignoreReadonly: true,
|
||||
format: 'L',
|
||||
showClear: true
|
||||
});
|
||||
element.find('#fromDatePicker').on('blur', function(){
|
||||
ctrl.pickUp({'key': 'fromDate', 'value': $(this).val()});
|
||||
});
|
||||
element.find('#toDatePicker').on('blur', function(){
|
||||
ctrl.pickUp({'key': 'toDate', 'value': $(this).val()});
|
||||
});
|
||||
|
||||
element.find('#txtSearchPolicyInput').on('keydown', function(e) {
|
||||
if($(this).is(':focus') && e.keyCode === 13) {
|
||||
ctrl.searchReplicationPolicy();
|
||||
} else {
|
||||
$timeout(function() {
|
||||
if(ctrl.replicationPolicyName.length === 0) {
|
||||
ctrl.searchReplicationPolicy();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
element.find('#txtSearchJobInput').on('keydown', function(e) {
|
||||
if($(this).is(':focus') && e.keyCode === 13) {
|
||||
ctrl.searchReplicationJob();
|
||||
} else {
|
||||
$timeout(function() {
|
||||
if(ctrl.replicationJobName.length === 0) {
|
||||
ctrl.searchReplicationJob();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.replication', [
|
||||
'harbor.services.replication.policy',
|
||||
'harbor.services.replication.job'
|
||||
]);
|
||||
|
||||
})();
|
@ -1,44 +0,0 @@
|
||||
<div class="tab-pane" id="repositories" element-height>
|
||||
<div class="col-xs-12 col-md-12 each-tab-pane">
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" id="txtSearchInput" class="form-control" placeholder="" ng-model="vm.filterInput" value="" size="30">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" ng-click="vm.searchRepo()"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane">
|
||||
<div class="sub-pane">
|
||||
<div ng-if="vm.repositories.length == 0" class="empty-hint">
|
||||
<h4 style="margin-top: 120px;" class="text-muted">// 'no_repositories' | tr //</h4>
|
||||
</div>
|
||||
<div ng-if="vm.repositories.length > 0" class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
||||
<div class="panel panel-default" ng-repeat="repo in vm.repositories">
|
||||
<div class="panel-heading" role="tab" id="heading//$index + 1//">
|
||||
<h4 class="panel-title">
|
||||
<div class="row">
|
||||
<div class="col-md-10" style="padding: 2px">
|
||||
<a ng-show="vm.tagCount[repo] > 0" role="button" data-toggle="collapse" data-parent="" href="?project_id=//vm.projectId//#collapse//$index + 1//" aria-expanded="true" aria-controls="collapse//$index+1//">
|
||||
<span class="glyphicon glyphicon-book"></span> //repo// <span class="badge">//vm.tagCount[repo]//</span>
|
||||
</a>
|
||||
<a ng-if="vm.tagCount[repo] === 0" role="button" style="text-decoration: none;" data-toggle="collapse" data-parent="" aria-expanded="true" aria-controls="collapse//$index+1//">
|
||||
<span class="glyphicon glyphicon-book"></span> //repo// <span class="badge">//vm.tagCount[repo]//</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-2" style="padding: 2px; padding-left: 6%;">
|
||||
|
||||
<input ng-if="vm.tagCount[repo] > 0 && vm.roleId == 1" type="checkbox" ng-checked="vm.selectAll[repo]" ng-click="vm.selectAllTags(repo)">
|
||||
<a ng-if="vm.tagCount[repo] > 0 && vm.roleId == 1 && vm.selectedTags[repo].length > 0" href="javascript:void(0)" ng-click="vm.deleteSelectedTagsByRepo(repo)" title="// 'delete_selected_tag' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[repo + '|']"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
<list-tag ng-show="vm.tagCount[repo] > 0" associate-id="$index + 1" repo-name="repo" tag-count="vm.tagCount" toggle-in-progress="vm.toggleInProgress" delete-by-tag="vm.deleteByTag()" role-id="//vm.roleId//"></list-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<paginator ng-if="vm.totalCount > 0" total-count="//vm.totalCount//" page-size="//vm.pageSize//" page="vm.page" display-count="5"></paginator>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.repository')
|
||||
.directive('listRepository', listRepository);
|
||||
|
||||
ListRepositoryController.$inject = ['$scope', 'ListRepositoryService', 'DeleteRepositoryService', '$filter', 'trFilter', '$location', 'getParameterByName', '$window'];
|
||||
|
||||
function ListRepositoryController($scope, ListRepositoryService, DeleteRepositoryService, $filter, trFilter, $location, getParameterByName, $window) {
|
||||
|
||||
$scope.subsTabPane = 30;
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.sectionHeight = {'min-height': '579px'};
|
||||
|
||||
vm.filterInput = '';
|
||||
vm.toggleInProgress = [];
|
||||
|
||||
var hashValue = $location.hash();
|
||||
if(hashValue) {
|
||||
var slashIndex = hashValue.indexOf('/');
|
||||
if(slashIndex >=0) {
|
||||
vm.filterInput = hashValue.substring(slashIndex + 1);
|
||||
}else{
|
||||
vm.filterInput = hashValue;
|
||||
}
|
||||
}
|
||||
vm.page = 1;
|
||||
vm.pageSize = 15;
|
||||
|
||||
vm.retrieve = retrieve;
|
||||
vm.searchRepo = searchRepo;
|
||||
vm.tagCount = {};
|
||||
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
|
||||
$scope.$on('retrieveData', function(e, val) {
|
||||
if(val) {
|
||||
vm.projectId = getParameterByName('project_id', $location.absUrl());
|
||||
vm.filterInput = '';
|
||||
vm.retrieve();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$scope.$watch('vm.repositories', function(current) {
|
||||
if(current) {
|
||||
vm.repositories = current || [];
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.page', function(current) {
|
||||
if(current) {
|
||||
vm.page = current;
|
||||
vm.retrieve();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.tagName', function(current) {
|
||||
if(current) {
|
||||
vm.selectedTags = [];
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('repoName', function(e, val) {
|
||||
vm.repoName = val;
|
||||
});
|
||||
|
||||
$scope.$on('tag', function(e, val){
|
||||
vm.tag = val;
|
||||
});
|
||||
|
||||
$scope.$on('tagCount', function(e, val) {
|
||||
vm.tagCount = val;
|
||||
});
|
||||
|
||||
$scope.$on('tags', function(e, val) {
|
||||
vm.tags = val;
|
||||
});
|
||||
|
||||
vm.deleteByRepo = deleteByRepo;
|
||||
vm.deleteByTag = deleteByTag;
|
||||
|
||||
vm.deleteSelectedTagsByRepo = deleteSelectedTagsByRepo;
|
||||
|
||||
vm.deleteImage = deleteImage;
|
||||
vm.deleteSelectedTags = deleteSelectedTags;
|
||||
|
||||
vm.selectAll = [];
|
||||
vm.selectAllTags = selectAllTags;
|
||||
|
||||
vm.selectedTags = [];
|
||||
|
||||
function retrieve(){
|
||||
console.log('retrieve repositories, project_id:' + vm.projectId);
|
||||
ListRepositoryService(vm.projectId, vm.filterInput, vm.page, vm.pageSize)
|
||||
.then(getRepositoryComplete, getRepositoryFailed);
|
||||
}
|
||||
|
||||
function getRepositoryComplete(response) {
|
||||
vm.repositories = response.data || [];
|
||||
vm.totalCount = response.headers('X-Total-Count');
|
||||
vm.selectAll[vm.repoName] = false;
|
||||
vm.selectedTags = [];
|
||||
}
|
||||
|
||||
function getRepositoryFailed(response) {
|
||||
var errorMessage = '';
|
||||
if(response.status === 404) {
|
||||
errorMessage = $filter('tr')('project_does_not_exist');
|
||||
}else{
|
||||
errorMessage = $filter('tr')('failed_to_get_project');
|
||||
}
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', errorMessage);
|
||||
var emitInfo = {
|
||||
'confirmOnly': true,
|
||||
'contentType': 'text/html',
|
||||
'action' : function() {
|
||||
$window.location.href = '/dashboard';
|
||||
}
|
||||
};
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
console.log('Failed to list repositories:' + response.data);
|
||||
}
|
||||
|
||||
function searchRepo() {
|
||||
$scope.$broadcast('refreshTags', true);
|
||||
vm.retrieve();
|
||||
}
|
||||
|
||||
function deleteByRepo(repoName) {
|
||||
vm.repoName = repoName;
|
||||
vm.tag = '';
|
||||
|
||||
$scope.$emit('modalTitle', $filter('tr')('alert_delete_repo_title', [repoName]));
|
||||
$scope.$emit('modalMessage', $filter('tr')('alert_delete_repo', [repoName]));
|
||||
|
||||
var emitInfo = {
|
||||
'confirmOnly': false,
|
||||
'contentType': 'text/html',
|
||||
'action' : vm.deleteImage
|
||||
};
|
||||
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
}
|
||||
|
||||
function deleteSelectedTagsByRepo(repo) {
|
||||
vm.repoName = repo;
|
||||
$scope.$broadcast('gatherSelectedTags' + vm.repoName, true);
|
||||
var emitInfo = {
|
||||
'confirmOnly': false,
|
||||
'contentType': 'text/html',
|
||||
'action' : vm.deleteSelectedTags
|
||||
};
|
||||
$scope.$emit('modalTitle', $filter('tr')('alert_delete_tag_title'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('alert_delete_selected_tag'));
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
}
|
||||
|
||||
function selectAllTags(repo) {
|
||||
vm.selectAll[repo] = !vm.selectAll[repo];
|
||||
console.log('send to tags selectAll:' + vm.selectAll[repo]);
|
||||
$scope.$broadcast('selectAll' + repo, {'status': vm.selectAll[repo], 'repoName': repo});
|
||||
}
|
||||
|
||||
$scope.$on('selectedAll', function(e, val) {
|
||||
console.log('received from tags selectedAll:' + angular.toJson(val));
|
||||
vm.selectAll[val.repoName] = val.status;
|
||||
});
|
||||
|
||||
function deleteByTag() {
|
||||
$scope.$emit('modalTitle', $filter('tr')('alert_delete_tag_title', [vm.tag]));
|
||||
var message;
|
||||
console.log('vm.tagCount:' + angular.toJson(vm.tagCount[vm.repoName]));
|
||||
$scope.$emit('modalMessage', $filter('tr')('alert_delete_tag', [vm.tag]));
|
||||
|
||||
var emitInfo = {
|
||||
'confirmOnly': false,
|
||||
'contentType': 'text/html',
|
||||
'action' : vm.deleteImage
|
||||
};
|
||||
$scope.$emit('raiseInfo', emitInfo);
|
||||
}
|
||||
|
||||
function deleteImage() {
|
||||
console.log('Delete image, repoName:' + vm.repoName + ', tag:' + vm.tag);
|
||||
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = true;
|
||||
DeleteRepositoryService(vm.repoName, vm.tag)
|
||||
.success(deleteRepositorySuccess)
|
||||
.error(deleteRepositoryFailed);
|
||||
}
|
||||
|
||||
$scope.$on('selectedTags', function(e, val) {
|
||||
if(val) {
|
||||
vm.selectedTags[val.repoName] = val.tags;
|
||||
}
|
||||
});
|
||||
|
||||
function deleteSelectedTags() {
|
||||
console.log('Delete selected tags:' + angular.toJson(vm.selectedTags[vm.repoName]) + ' under repo:' + vm.repoName);
|
||||
vm.toggleInProgress[vm.repoName + '|'] = true;
|
||||
for(var i in vm.selectedTags[vm.repoName] || []) {
|
||||
var tag = vm.selectedTags[vm.repoName][i];
|
||||
if(tag !== '') {
|
||||
vm.toggleInProgress[vm.repoName + '|' + tag] = true;
|
||||
DeleteRepositoryService(vm.repoName, tag)
|
||||
.success(deleteRepositorySuccess)
|
||||
.error(deleteRepositoryFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteRepositorySuccess(data, status) {
|
||||
vm.toggleInProgress[vm.repoName + '|'] = false;
|
||||
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false;
|
||||
vm.retrieve();
|
||||
$scope.$broadcast('refreshTags', true);
|
||||
}
|
||||
|
||||
function deleteRepositoryFailed(data, status) {
|
||||
vm.toggleInProgress[vm.repoName + '|'] = false;
|
||||
vm.toggleInProgress[vm.repoName + '|' + vm.tag] = false;
|
||||
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
var message;
|
||||
if(status === 401) {
|
||||
message = $filter('tr')('failed_to_delete_repo_insuffient_permissions');
|
||||
}else{
|
||||
message = $filter('tr')('failed_to_delete_repo');
|
||||
}
|
||||
$scope.$emit('modalMessage', message);
|
||||
$scope.$emit('raiseError', true);
|
||||
|
||||
console.log('Failed to delete repository:' + angular.toJson(data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
listRepository.$inject = ['$timeout'];
|
||||
|
||||
function listRepository($timeout) {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/repository/list-repository.directive.html',
|
||||
'scope': {
|
||||
'sectionHeight': '=',
|
||||
'roleId': '@'
|
||||
},
|
||||
'link': link,
|
||||
'controller': ListRepositoryController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attr, ctrl) {
|
||||
element.find('#txtSearchInput').on('keydown', function(e) {
|
||||
if($(this).is(':focus') && e.keyCode === 13) {
|
||||
ctrl.retrieve();
|
||||
} else {
|
||||
$timeout(function() {
|
||||
if(ctrl.filterInput.length === 0) {
|
||||
ctrl.retrieve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,26 +0,0 @@
|
||||
<div id="collapse//vm.associateId//" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading//vm.associateId//">
|
||||
<div class="panel-body table-responsive">
|
||||
<table class="table" style="margin-bottom: 0;">
|
||||
<thead>
|
||||
<th width="20%"><span class="glyphicon glyphicon-tags"></span> // 'tag' | tr //</th>
|
||||
<th width="15%" style="text-align: center;">// 'image_details' | tr //</th>
|
||||
<th width="40%">// 'pull_command' | tr //</th>
|
||||
<th width="15%" ng-if="vm.roleId == 1" style="text-align: center;">// 'operation' | tr //</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="tag in vm.tags">
|
||||
<td>//tag//</td>
|
||||
<td style="text-align: center;"><popup-details repo-name="//vm.repoName//" tag="//tag//" index="//$index//"></popup-details></td>
|
||||
<td>
|
||||
<pull-command repo-name="//vm.repoName//" tag="//tag//"></pull-command>
|
||||
</td>
|
||||
<td style="padding: 2px; padding-left: 6%;">
|
||||
|
||||
<input ng-if="vm.roleId == 1" type="checkbox" ng-checked="vm.selected[vm.repoName][$index]" ng-click="vm.selectOne($index, tag)">
|
||||
<a ng-show="vm.roleId == 1 && vm.selected[vm.repoName][$index]" href="javascript:void(0);" ng-click="vm.deleteTag({repoName: vm.repoName, tag: tag})" title="// 'delete_tag' | tr //" loading-progress hide-target="true" toggle-in-progress="vm.toggleInProgress[vm.repoName +'|'+ tag]"><span class="glyphicon glyphicon-trash"></span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.repository')
|
||||
.directive('listTag', listTag);
|
||||
|
||||
ListTagController.$inject = ['$scope', 'ListTagService', '$filter', 'trFilter'];
|
||||
|
||||
function ListTagController($scope, ListTagService, $filter, trFilter) {
|
||||
var vm = this;
|
||||
|
||||
vm.tags = [];
|
||||
vm.retrieve = retrieve;
|
||||
|
||||
vm.selected = [];
|
||||
vm.selected[vm.repoName] = [];
|
||||
|
||||
vm.selectedTags = [];
|
||||
|
||||
$scope.$watch('vm.repoName', function(current, origin) {
|
||||
if(current) {
|
||||
console.log('vm.repoName triggered tags retrieval.');
|
||||
vm.retrieve();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('refreshTags', function(e, val) {
|
||||
if(val) {
|
||||
vm.retrieve();
|
||||
vm.selectedCount[vm.repoName] = 0;
|
||||
vm.selected[val.repoName] = [];
|
||||
vm.selectedTags = [];
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('vm.selectedCount[vm.repoName]', function(current, previous) {
|
||||
if(current !== previous) {
|
||||
console.log('Watching vm.selectedCount:' + current);
|
||||
$scope.$emit('selectedAll', {'status': (current === vm.tags.length), 'repoName': vm.repoName});
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('gatherSelectedTags' + vm.repoName, function(e, val) {
|
||||
if(val) {
|
||||
console.log('RECEIVED gatherSelectedTags:' + val);
|
||||
gatherSelectedTags();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('selectAll' + vm.repoName, function(e, val) {
|
||||
(val.status) ? vm.selectedCount[val.repoName] = vm.tags.length : vm.selectedCount[val.repoName] = 0;
|
||||
for(var i = 0; i < vm.tags.length; i++) {
|
||||
vm.selected[val.repoName][i] = val.status;
|
||||
}
|
||||
gatherSelectedTags();
|
||||
console.log('received selectAll:' + angular.toJson(val) + ', vm.selected:' + angular.toJson(vm.selected));
|
||||
});
|
||||
|
||||
$scope.$watch('vm.tags', function(current) {
|
||||
if(current) {
|
||||
vm.tags = current;
|
||||
}
|
||||
});
|
||||
|
||||
vm.deleteTag = deleteTag;
|
||||
|
||||
vm.selectedCount = [];
|
||||
vm.selectedCount[vm.repoName] = 0;
|
||||
|
||||
vm.selectOne = selectOne;
|
||||
|
||||
function retrieve() {
|
||||
ListTagService(vm.repoName)
|
||||
.success(getTagSuccess)
|
||||
.error(getTagFailed);
|
||||
}
|
||||
|
||||
function getTagSuccess(data) {
|
||||
vm.tags = data || [];
|
||||
vm.tagCount[vm.repoName] = vm.tags.length;
|
||||
|
||||
$scope.$emit('tags', vm.tags);
|
||||
$scope.$emit('tagCount', vm.tagCount);
|
||||
|
||||
angular.forEach(vm.tags, function(item) {
|
||||
vm.toggleInProgress[vm.repoName + '|' + item] = false;
|
||||
});
|
||||
|
||||
for(var i = 0; i < vm.tags.length; i++) {
|
||||
vm.selected[vm.repoName][i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getTagFailed(data) {
|
||||
$scope.$emit('modalTitle', $filter('tr')('error'));
|
||||
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_tag'));
|
||||
$scope.$emit('raiseError', true);
|
||||
console.log('Failed to get tags:' + data);
|
||||
}
|
||||
|
||||
function deleteTag(e) {
|
||||
$scope.$emit('repoName', e.repoName);
|
||||
$scope.$emit('tag', e.tag);
|
||||
vm.deleteByTag();
|
||||
}
|
||||
|
||||
function selectOne(index, tagName) {
|
||||
vm.selected[vm.repoName][index] = !vm.selected[vm.repoName][index];
|
||||
(vm.selected[vm.repoName][index]) ? ++vm.selectedCount[vm.repoName] : --vm.selectedCount[vm.repoName];
|
||||
console.log('selectOne, repoName:' + vm.repoName + ', vm.selected:' + vm.selected[vm.repoName][index] + ', index:' + index + ', length:' + vm.selectedCount[vm.repoName]);
|
||||
gatherSelectedTags();
|
||||
}
|
||||
|
||||
function gatherSelectedTags() {
|
||||
vm.selectedTags[vm.repoName] = [];
|
||||
for(var i = 0; i < vm.tags.length; i++) {
|
||||
(vm.selected[vm.repoName][i]) ? vm.selectedTags[vm.repoName][i] = vm.tags[i] : vm.selectedTags[vm.repoName][i] = '';
|
||||
}
|
||||
var tagsToDelete = [];
|
||||
for(var i in vm.selectedTags[vm.repoName]) {
|
||||
var tag = vm.selectedTags[vm.repoName][i];
|
||||
if(tag !== '') {
|
||||
tagsToDelete.push(tag);
|
||||
}
|
||||
}
|
||||
$scope.$emit('selectedTags', {'repoName': vm.repoName, 'tags': tagsToDelete});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function listTag() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/resources/js/components/repository/list-tag.directive.html',
|
||||
'scope': {
|
||||
'tagCount': '=',
|
||||
'associateId': '=',
|
||||
'repoName': '=',
|
||||
'toggleInProgress': '=',
|
||||
'deleteByTag': '&',
|
||||
'roleId': '@'
|
||||
},
|
||||
'replace': true,
|
||||
'controller': ListTagController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,3 +0,0 @@
|
||||
<a href="javascript:void(0);" role="button" tabindex="0" data-trigger="click" data-toggle="popover" data-placement="right">
|
||||
<span class="glyphicon glyphicon-info-sign"></span>
|
||||
</a>
|