Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
凌波微步_大先生
dashboard
提交
70b03fc1
D
dashboard
项目概览
凌波微步_大先生
/
dashboard
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dashboard
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
70b03fc1
编写于
12月 03, 2015
作者:
P
Piotr Bryk
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #110 from floreks/deploy-form-labels
Added labels handling in the deploy form.
上级
bf61ab47
11f1257e
变更
19
隐藏空白更改
内联
并排
Showing
19 changed file
with
512 addition
and
11 deletion
+512
-11
src/app/backend/deploy.go
src/app/backend/deploy.go
+24
-2
src/app/externs/backendapi.js
src/app/externs/backendapi.js
+10
-1
src/app/frontend/.eslintrc
src/app/frontend/.eslintrc
+3
-0
src/app/frontend/deploy/deploy.html
src/app/frontend/deploy/deploy.html
+1
-1
src/app/frontend/deploy/deploy_controller.js
src/app/frontend/deploy/deploy_controller.js
+4
-1
src/app/frontend/deploy/deploy_module.js
src/app/frontend/deploy/deploy_module.js
+4
-1
src/app/frontend/deploy/deployfromsettings.html
src/app/frontend/deploy/deployfromsettings.html
+12
-0
src/app/frontend/deploy/deployfromsettings_controller.js
src/app/frontend/deploy/deployfromsettings_controller.js
+56
-0
src/app/frontend/deploy/deploylabel.html
src/app/frontend/deploy/deploylabel.html
+36
-0
src/app/frontend/deploy/deploylabel.js
src/app/frontend/deploy/deploylabel.js
+69
-0
src/app/frontend/deploy/deploylabel.scss
src/app/frontend/deploy/deploylabel.scss
+20
-0
src/app/frontend/deploy/deploylabel_controller.js
src/app/frontend/deploy/deploylabel_controller.js
+158
-0
src/app/frontend/deploy/deploylabel_directive.js
src/app/frontend/deploy/deploylabel_directive.js
+33
-0
src/test/frontend/.eslintrc
src/test/frontend/.eslintrc
+1
-2
src/test/frontend/deploy/deployfromsettings_controller_test.js
...est/frontend/deploy/deployfromsettings_controller_test.js
+51
-0
src/test/frontend/zerostate/zerostate_controller_test.js
src/test/frontend/zerostate/zerostate_controller_test.js
+3
-3
src/test/integration/deploy/deploy_test.js
src/test/integration/deploy/deploy_test.js
+27
-0
src/test/integration/zerostate/zerostate_po.js
src/test/integration/zerostate/zerostate_po.js
+0
-0
src/test/integration/zerostate/zerostate_test.js
src/test/integration/zerostate/zerostate_test.js
+0
-0
未找到文件。
src/app/backend/deploy.go
浏览文件 @
70b03fc1
...
@@ -22,7 +22,6 @@ import (
...
@@ -22,7 +22,6 @@ import (
const
(
const
(
DescriptionAnnotationKey
=
"description"
DescriptionAnnotationKey
=
"description"
NameLabelKey
=
"name"
)
)
// Specification for an app deployment.
// Specification for an app deployment.
...
@@ -48,6 +47,9 @@ type AppDeploymentSpec struct {
...
@@ -48,6 +47,9 @@ type AppDeploymentSpec struct {
// Target namespace of the application.
// Target namespace of the application.
Namespace
string
`json:"namespace"`
Namespace
string
`json:"namespace"`
// Labels that will be defined on Pods/RCs/Services
Labels
[]
Label
`json:"labels"`
}
}
// Port mapping for an application deployment.
// Port mapping for an application deployment.
...
@@ -62,13 +64,22 @@ type PortMapping struct {
...
@@ -62,13 +64,22 @@ type PortMapping struct {
Protocol
api
.
Protocol
`json:"protocol"`
Protocol
api
.
Protocol
`json:"protocol"`
}
}
// Structure representing label assignable to Pod/RC/Service
type
Label
struct
{
// Label key
Key
string
`json:"key"`
// Label value
Value
string
`json:"value"`
}
// Deploys an app based on the given configuration. The app is deployed using the given client.
// Deploys an app based on the given configuration. The app is deployed using the given client.
// App deployment consists of a replication controller and an optional service. Both of them share
// App deployment consists of a replication controller and an optional service. Both of them share
// common labels.
// common labels.
// TODO(bryk): Write tests for this function.
// TODO(bryk): Write tests for this function.
func
DeployApp
(
spec
*
AppDeploymentSpec
,
client
*
client
.
Client
)
error
{
func
DeployApp
(
spec
*
AppDeploymentSpec
,
client
*
client
.
Client
)
error
{
annotations
:=
map
[
string
]
string
{
DescriptionAnnotationKey
:
spec
.
Description
}
annotations
:=
map
[
string
]
string
{
DescriptionAnnotationKey
:
spec
.
Description
}
labels
:=
map
[
string
]
string
{
NameLabelKey
:
spec
.
Name
}
labels
:=
getLabelsMap
(
spec
.
Labels
)
objectMeta
:=
api
.
ObjectMeta
{
objectMeta
:=
api
.
ObjectMeta
{
Annotations
:
annotations
,
Annotations
:
annotations
,
Name
:
spec
.
Name
,
Name
:
spec
.
Name
,
...
@@ -137,3 +148,14 @@ func DeployApp(spec *AppDeploymentSpec, client *client.Client) error {
...
@@ -137,3 +148,14 @@ func DeployApp(spec *AppDeploymentSpec, client *client.Client) error {
return
nil
return
nil
}
}
}
}
// Converts array of labels to map[string]string
func
getLabelsMap
(
labels
[]
Label
)
map
[
string
]
string
{
result
:=
make
(
map
[
string
]
string
)
for
_
,
label
:=
range
labels
{
result
[
label
.
Key
]
=
label
.
Value
}
return
result
}
src/app/externs/backendapi.js
浏览文件 @
70b03fc1
...
@@ -41,7 +41,8 @@ backendApi.PortMapping;
...
@@ -41,7 +41,8 @@ backendApi.PortMapping;
* description: string,
* description: string,
* portMappings: !Array<!backendApi.PortMapping>,
* portMappings: !Array<!backendApi.PortMapping>,
* replicas: number,
* replicas: number,
* namespace: string
* namespace: string,
* labels: !Array<!backendApi.Label>
* }}
* }}
*/
*/
backendApi
.
AppDeploymentSpec
;
backendApi
.
AppDeploymentSpec
;
...
@@ -106,3 +107,11 @@ backendApi.NamespaceSpec;
...
@@ -106,3 +107,11 @@ backendApi.NamespaceSpec;
* }}
* }}
*/
*/
backendApi
.
NamespaceList
;
backendApi
.
NamespaceList
;
/**
* @typedef {{
* key: string,
* value: string
* }}
*/
backendApi
.
Label
;
src/app/frontend/.eslintrc
浏览文件 @
70b03fc1
...
@@ -10,5 +10,8 @@
...
@@ -10,5 +10,8 @@
"angular/module-getter": 0,
"angular/module-getter": 0,
// Disable undefined variable checking. This is done by the compiler.
// Disable undefined variable checking. This is done by the compiler.
"no-undef": 0,
"no-undef": 0,
// To allow comparison to undefined variable, because Google Closure Compiler does not
// understand angular.isDefined correctly.
"angular/definedundefined": 0,
}
}
}
}
src/app/frontend/deploy/deploy.html
浏览文件 @
70b03fc1
...
@@ -17,7 +17,7 @@ limitations under the License.
...
@@ -17,7 +17,7 @@ limitations under the License.
<div
layout=
"column"
layout-padding
layout-align=
"center center"
>
<div
layout=
"column"
layout-padding
layout-align=
"center center"
>
<md-whiteframe
class=
"kd-deploy-whiteframe md-whiteframe-5dp"
flex
flex-gt-md
>
<md-whiteframe
class=
"kd-deploy-whiteframe md-whiteframe-5dp"
flex
flex-gt-md
>
<h3
class=
"md-headline"
>
Deploy a Containerized App
</h3>
<h3
class=
"md-headline"
>
Deploy a Containerized App
</h3>
<form
ng-submit=
"ctrl.deployBySelection()"
>
<form
n
ame=
"ctrl.deployForm"
n
g-submit=
"ctrl.deployBySelection()"
>
<md-input-container
class=
"md-block"
>
<md-input-container
class=
"md-block"
>
<label>
App name
</label>
<label>
App name
</label>
<input
ng-model=
"ctrl.name"
required
>
<input
ng-model=
"ctrl.name"
required
>
...
...
src/app/frontend/deploy/deploy_controller.js
浏览文件 @
70b03fc1
...
@@ -30,6 +30,9 @@ export default class DeployController {
...
@@ -30,6 +30,9 @@ export default class DeployController {
* @ngInject
* @ngInject
*/
*/
constructor
(
$resource
,
$log
,
$state
,
$mdDialog
,
namespaces
)
{
constructor
(
$resource
,
$log
,
$state
,
$mdDialog
,
namespaces
)
{
/** @export {!angular.FormController} Initialized from the template */
this
.
deployForm
;
/** @export {string} */
/** @export {string} */
this
.
name
=
''
;
this
.
name
=
''
;
...
@@ -108,7 +111,7 @@ export default class DeployController {
...
@@ -108,7 +111,7 @@ export default class DeployController {
* @return {boolean}
* @return {boolean}
* @export
* @export
*/
*/
isDeployDisabled
()
{
return
this
.
isDeployInProgress_
;
}
isDeployDisabled
()
{
return
this
.
isDeployInProgress_
||
this
.
deployForm
.
$invalid
;
}
/**
/**
* Cancels the deployment form.
* Cancels the deployment form.
...
...
src/app/frontend/deploy/deploy_module.js
浏览文件 @
70b03fc1
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
import
stateConfig
from
'
./deploy_state
'
;
import
stateConfig
from
'
./deploy_state
'
;
import
deployFromSettingsDirective
from
'
./deployfromsettings_directive
'
;
import
deployFromSettingsDirective
from
'
./deployfromsettings_directive
'
;
import
deployLabelDirective
from
'
./deploylabel_directive
'
;
/**
/**
* Angular module for the deploy view.
* Angular module for the deploy view.
...
@@ -24,7 +25,9 @@ export default angular.module(
...
@@ -24,7 +25,9 @@ export default angular.module(
'
kubernetesDashboard.deploy
'
,
'
kubernetesDashboard.deploy
'
,
[
[
'
ngMaterial
'
,
'
ngMaterial
'
,
'
ngResource
'
,
'
ui.router
'
,
'
ui.router
'
,
])
])
.
config
(
stateConfig
)
.
config
(
stateConfig
)
.
directive
(
'
deployFromSettings
'
,
deployFromSettingsDirective
);
.
directive
(
'
deployFromSettings
'
,
deployFromSettingsDirective
)
.
directive
(
'
kdLabel
'
,
deployLabelDirective
);
src/app/frontend/deploy/deployfromsettings.html
浏览文件 @
70b03fc1
...
@@ -47,3 +47,15 @@ limitations under the License.
...
@@ -47,3 +47,15 @@ limitations under the License.
<label>
Description (optional)
</label>
<label>
Description (optional)
</label>
<textarea
ng-model=
"ctrl.description"
></textarea>
<textarea
ng-model=
"ctrl.description"
></textarea>
</md-input-container>
</md-input-container>
<div>
<div>
Labels (optional)
</div>
<div
layout=
"column"
>
<div
layout=
"row"
>
<p
flex
>
Key
</p>
<p
flex
>
Value
</p>
</div>
<div
ng-repeat=
"label in ctrl.labels"
>
<kd-label
layout=
"row"
flex
label=
"label"
labels=
"ctrl.labels"
></kd-label>
</div>
</div>
</div>
src/app/frontend/deploy/deployfromsettings_controller.js
浏览文件 @
70b03fc1
...
@@ -12,8 +12,13 @@
...
@@ -12,8 +12,13 @@
// See the License for the specific language governing permissions and
// See the License for the specific language governing permissions and
// limitations under the License.
// limitations under the License.
import
DeployLabel
from
'
./deploylabel
'
;
import
{
stateName
as
replicasetliststate
}
from
'
replicasetlist/replicasetlist_state
'
;
import
{
stateName
as
replicasetliststate
}
from
'
replicasetlist/replicasetlist_state
'
;
// Label keys for predefined labels
export
const
APP_LABEL_KEY
=
'
app
'
;
export
const
VERSION_LABEL_KEY
=
'
version
'
;
/**
/**
* Controller for the deploy from settings directive.
* Controller for the deploy from settings directive.
*
*
...
@@ -68,6 +73,13 @@ export default class DeployFromSettingsController {
...
@@ -68,6 +73,13 @@ export default class DeployFromSettingsController {
/** @export {boolean} */
/** @export {boolean} */
this
.
isExternal
=
false
;
this
.
isExternal
=
false
;
/** @export {!Array<!DeployLabel>} */
this
.
labels
=
[
new
DeployLabel
(
APP_LABEL_KEY
,
''
,
false
,
this
.
getName_
.
bind
(
this
)),
new
DeployLabel
(
VERSION_LABEL_KEY
,
''
,
false
,
this
.
getContainerImageVersion_
.
bind
(
this
)),
new
DeployLabel
(),
];
}
}
/**
/**
...
@@ -87,6 +99,7 @@ export default class DeployFromSettingsController {
...
@@ -87,6 +99,7 @@ export default class DeployFromSettingsController {
portMappings
:
this
.
portMappings
.
filter
(
this
.
isPortMappingEmpty_
),
portMappings
:
this
.
portMappings
.
filter
(
this
.
isPortMappingEmpty_
),
replicas
:
this
.
replicas
,
replicas
:
this
.
replicas
,
namespace
:
this
.
namespace
,
namespace
:
this
.
namespace
,
labels
:
this
.
toBackendApiLabels_
(
this
.
labels
),
};
};
let
defer
=
this
.
q_
.
defer
();
let
defer
=
this
.
q_
.
defer
();
...
@@ -107,6 +120,22 @@ export default class DeployFromSettingsController {
...
@@ -107,6 +120,22 @@ export default class DeployFromSettingsController {
return
defer
.
promise
;
return
defer
.
promise
;
}
}
/**
* Converts array of DeployLabel to array of backend api label
* @param {!Array<!DeployLabel>} labels
* @return {!Array<!backendApi.Label>}
* @private
*/
toBackendApiLabels_
(
labels
)
{
// Omit labels with empty key/value
/** @type {!Array<!DeployLabel>} */
let
apiLabels
=
labels
.
filter
((
label
)
=>
{
return
label
.
key
.
length
!==
0
&&
label
.
value
().
length
!==
0
;
});
// Transform to array of backend api labels
return
apiLabels
.
map
((
label
)
=>
{
return
label
.
toBackendApi
();
});
}
/**
/**
* @param {string} defaultProtocol
* @param {string} defaultProtocol
* @return {!backendApi.PortMapping}
* @return {!backendApi.PortMapping}
...
@@ -123,4 +152,31 @@ export default class DeployFromSettingsController {
...
@@ -123,4 +152,31 @@ export default class DeployFromSettingsController {
* @private
* @private
*/
*/
isPortMappingEmpty_
(
portMapping
)
{
return
!!
portMapping
.
port
&&
!!
portMapping
.
targetPort
;
}
isPortMappingEmpty_
(
portMapping
)
{
return
!!
portMapping
.
port
&&
!!
portMapping
.
targetPort
;
}
/**
* Callbacks used in DeployLabel model to make it aware of controller state changes.
*/
/**
* Returns extracted from link container image version.
* @return {string}
* @private
*/
getContainerImageVersion_
()
{
/** @type {number} */
let
index
=
(
this
.
containerImage
||
''
).
lastIndexOf
(
'
:
'
);
if
(
index
>
-
1
)
{
return
this
.
containerImage
.
substring
(
index
+
1
);
}
return
''
;
}
/**
* Returns application name.
* @return {string}
* @private
*/
getName_
()
{
return
this
.
name
;
}
}
}
src/app/frontend/deploy/deploylabel.html
0 → 100644
浏览文件 @
70b03fc1
<!--
Copyright 2015 Google 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-form
layout=
"row"
flex
name=
"labelForm"
>
<md-input-container
md-no-float
class=
"md-block"
flex=
"45"
>
<input
name=
"key"
ng-model=
"labelCtrl.label.key"
ng-change=
"labelCtrl.check(labelForm)"
placeholder=
"{{labelCtrl.label.key}}"
ng-disabled=
"!labelCtrl.label.editable"
>
<ng-messages
for=
"labelForm.key.$error"
ng-if=
"labelForm.key.$invalid"
>
<ng-message
when=
"unique"
>
{{labelCtrl.label.key}} is not unique.
</ng-message>
</ng-messages>
</md-input-container>
<p
flex=
"5"
></p>
<md-input-container
md-no-float
class=
"md-block"
flex=
"40"
>
<input
ng-model=
"labelCtrl.label.value"
ng-change=
"labelCtrl.check()"
placeholder=
"{{labelCtrl.label.value}}"
ng-disabled=
"!labelCtrl.label.editable"
ng-model-options=
"{ getterSetter: true }"
>
<ng-messages
ng-if=
"labelForm.key.$error.unique"
></ng-messages>
</md-input-container>
<md-button
type=
"button"
ng-show=
"labelCtrl.isRemovable()"
ng-click=
"labelCtrl.deleteLabel()"
class=
"material-icons kd-deploy-labels-button"
>
delete
</md-button>
</ng-form>
src/app/frontend/deploy/deploylabel.js
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
/**
* Represents label object used in deploy form view.
* @final
*/
export
default
class
DeployLabel
{
/**
* Constructs DeployLabel object.
* @param {string} key
* @param {string} value
* @param {boolean} editable
* @param {function(string): string} derivedValueGetterFn - callback
*/
constructor
(
key
=
''
,
value
=
''
,
editable
=
true
,
derivedValueGetterFn
=
undefined
)
{
/** @export {boolean} */
this
.
editable
=
editable
;
/** @export {string} */
this
.
key
=
key
;
/** @private {string} */
this
.
value_
=
value
;
/** @private {function(string): string|undefined} */
this
.
derivedValueGetter_
=
derivedValueGetterFn
;
}
/**
* @param {string} [newValue]
* @return {string}
* @export
*/
value
(
newValue
)
{
if
(
this
.
derivedValueGetter_
!==
undefined
)
{
if
(
newValue
!==
undefined
)
{
throw
Error
(
"
Can not set value of derived label.
"
);
}
return
this
.
derivedValueGetter_
(
this
.
key
);
}
return
newValue
!==
undefined
?
(
this
.
value_
=
newValue
)
:
this
.
value_
;
}
/**
* Converts 'this' object to backendApi.Label object.
* @return {!backendApi.Label}
* @export
*/
toBackendApi
()
{
return
{
key
:
this
.
key
,
value
:
this
.
value
(),
};
}
}
src/app/frontend/deploy/deploylabel.scss
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
.kd-deploy-labels-button
{
min-width
:
10px
;
margin
:
0
;
padding
:
0
;
height
:
10px
;
}
src/app/frontend/deploy/deploylabel_controller.js
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
import
DeployLabel
from
'
./deploylabel
'
;
/**
* Service used for handling label actions like: hover, showing duplicated key error, etc.
* @final
*/
export
default
class
DeployLabelController
{
/**
* Constructs our label controller.
*/
constructor
()
{
/** @export {!DeployLabel} Initialized from the scope. */
this
.
label
;
/** @export {!Array<!DeployLabel>} Initialized from the scope. */
this
.
labels
;
}
/**
* Calls checks on label:
* - adds label if last empty label has been filled
* - removes label if some label in the middle has key and value empty
* - checks for duplicated key and sets validity of element
* @param {!angular.FormController|undefined} labelForm
* @export
*/
check
(
labelForm
)
{
this
.
addIfNeeded_
();
this
.
removeIfNeeded_
();
this
.
validateKey_
(
labelForm
);
}
/**
* Returns true when label is editable and is not last on the list.
* Used to indicate whether delete icon should be shown near label.
* @return {boolean}
* @export
*/
isRemovable
()
{
/** @type {!DeployLabel} */
let
lastElement
=
this
.
labels
[
this
.
labels
.
length
-
1
];
return
!!
(
this
.
label
.
editable
&&
this
.
label
!==
lastElement
);
}
/**
* Deletes row from labels list.
* @export
*/
deleteLabel
()
{
/** @type {number} */
let
rowIdx
=
this
.
labels
.
indexOf
(
this
.
label
);
if
(
rowIdx
>
-
1
)
{
this
.
labels
.
splice
(
rowIdx
,
1
);
}
}
/**
* Adds label if last label key and value has been filled.
* @private
*/
addIfNeeded_
()
{
/** @type {!DeployLabel} */
let
lastLabel
=
this
.
labels
[
this
.
labels
.
length
-
1
];
if
(
this
.
isFilled_
(
lastLabel
))
{
this
.
addNewLabel_
();
}
}
/**
* Adds row to labels list.
* @private
*/
addNewLabel_
()
{
this
.
labels
.
push
(
new
DeployLabel
());
}
/**
* Removes label from labels list if label is empty and is not last label.
* @private
*/
removeIfNeeded_
()
{
/** @type {!DeployLabel} */
let
lastLabel
=
this
.
labels
[
this
.
labels
.
length
-
1
];
if
(
this
.
isEmpty_
(
this
.
label
)
&&
this
.
label
!==
lastLabel
)
{
this
.
deleteLabel
();
}
}
/**
* Validates label withing label form.
* Current checks:
* - duplicated key
* @param {!angular.FormController|undefined} labelForm
* @private
*/
validateKey_
(
labelForm
)
{
if
(
angular
.
isDefined
(
labelForm
))
{
/** @type {!angular.NgModelController} */
let
elem
=
labelForm
.
key
;
// TODO(floreks): Validate label key/value.
/** @type {boolean} */
let
isValid
=
!
this
.
isDuplicated_
();
elem
.
$setValidity
(
'
unique
'
,
isValid
);
}
}
/**
* Returns true if there are 2 or more labels with the same key on the labelList,
* false otherwise.
* @return {boolean}
* @private
*/
isDuplicated_
()
{
/** @type {number} */
let
duplications
=
0
;
this
.
labels
.
forEach
((
label
)
=>
{
if
(
this
.
label
.
key
.
length
!==
0
&&
label
.
key
===
this
.
label
.
key
)
{
duplications
++
;
}
});
return
duplications
>
1
;
}
/**
* Returns true if label key and value are empty, false otherwise.
* @param {!DeployLabel} label
* @return {boolean}
* @private
*/
isEmpty_
(
label
)
{
return
label
.
key
.
length
===
0
&&
label
.
value
().
length
===
0
;
}
/**
* Returns true if label key and value are not empty, false otherwise.
* @param {!DeployLabel} label
* @return {boolean}
* @private
*/
isFilled_
(
label
)
{
return
label
.
key
.
length
!==
0
&&
label
.
value
().
length
!==
0
;
}
}
src/app/frontend/deploy/deploylabel_directive.js
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
import
DeployLabelController
from
'
./deploylabel_controller
'
;
/**
* Returns directive definition for deploy form label.
*
* @return {!angular.Directive}
*/
export
default
function
labelDirective
()
{
return
{
controller
:
DeployLabelController
,
controllerAs
:
'
labelCtrl
'
,
templateUrl
:
'
deploy/deploylabel.html
'
,
scope
:
{},
bindToController
:
{
label
:
'
=
'
,
labels
:
'
=
'
,
},
};
}
src/test/frontend/.eslintrc
浏览文件 @
70b03fc1
...
@@ -4,7 +4,6 @@
...
@@ -4,7 +4,6 @@
},
},
// Define missing global Angular testing environment variables.
// Define missing global Angular testing environment variables.
"globals": {
"globals": {
"inject": true,
"angular": true,
"module": true,
},
},
}
}
src/test/frontend/deploy/deployfromsettings_controller_test.js
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
import
DeployFromSettingController
from
'
deploy/deployfromsettings_controller
'
;
import
deployModule
from
'
deploy/deploy_module
'
;
describe
(
'
DeployFromSettings controller
'
,
()
=>
{
let
ctrl
;
beforeEach
(()
=>
{
angular
.
mock
.
module
(
deployModule
.
name
);
angular
.
mock
.
inject
((
$log
,
$state
,
$resource
,
$q
)
=>
{
ctrl
=
new
DeployFromSettingController
(
$log
,
$state
,
$resource
,
$q
);
});
});
it
(
'
should return empty string when containerImage is undefined
'
,
()
=>
{
ctrl
.
containerImage
=
undefined
;
expect
(
ctrl
.
getContainerImageVersion_
()).
toEqual
(
''
);
});
it
(
'
should return empty string when containerImage is empty
'
,
()
=>
{
ctrl
.
containerImage
=
''
;
expect
(
ctrl
.
getContainerImageVersion_
()).
toEqual
(
''
);
});
it
(
'
should return empty string when containerImage is not empty and does not contain `:`
'
+
'
delimiter
'
,
()
=>
{
ctrl
.
containerImage
=
'
test
'
;
expect
(
ctrl
.
getContainerImageVersion_
()).
toEqual
(
''
);
});
it
(
'
should return part of the string after `:` delimiter
'
,
()
=>
{
ctrl
.
containerImage
=
'
test:1
'
;
expect
(
ctrl
.
getContainerImageVersion_
()).
toEqual
(
'
1
'
);
});
});
src/test/frontend/zerostate/zerostate_controller_test.js
浏览文件 @
70b03fc1
...
@@ -15,12 +15,12 @@
...
@@ -15,12 +15,12 @@
import
ZerostateController
from
'
zerostate/zerostate_controller
'
;
import
ZerostateController
from
'
zerostate/zerostate_controller
'
;
describe
(
'
Main controller
'
,
()
=>
{
describe
(
'
Main controller
'
,
()
=>
{
let
vm
;
let
ctrl
;
beforeEach
(
inject
((
$timeout
)
=>
{
vm
=
new
ZerostateController
(
$timeout
);
}));
beforeEach
(
angular
.
mock
.
inject
(()
=>
{
ctrl
=
new
ZerostateController
(
);
}));
it
(
'
should do something
'
,
()
=>
{
it
(
'
should do something
'
,
()
=>
{
expect
(
vm
.
learnMoreLinks
).
toEqual
([
expect
(
ctrl
.
learnMoreLinks
).
toEqual
([
{
title
:
'
Dashboard Tour
'
,
link
:
"
#
"
},
{
title
:
'
Dashboard Tour
'
,
link
:
"
#
"
},
{
title
:
'
Deploying your App
'
,
link
:
"
#
"
},
{
title
:
'
Deploying your App
'
,
link
:
"
#
"
},
{
title
:
'
Monitoring your App
'
,
link
:
"
#
"
},
{
title
:
'
Monitoring your App
'
,
link
:
"
#
"
},
...
...
src/test/integration/deploy/deploy_test.js
0 → 100644
浏览文件 @
70b03fc1
// Copyright 2015 Google 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.
describe
(
'
Deploy view
'
,
function
()
{
beforeEach
(
function
()
{
browser
.
get
(
'
#/deploy
'
);
});
it
(
'
should not contain errors in console
'
,
function
()
{
browser
.
manage
().
logs
().
get
(
'
browser
'
).
then
(
function
(
browserLog
)
{
// Filter and search for errors logs
let
filteredLogs
=
browserLog
.
filter
((
log
)
=>
{
return
log
.
level
.
value
>
900
;
});
// Expect no error logs
expect
(
filteredLogs
.
length
).
toBe
(
0
);
});
});
});
src/test/integration/zerostate_po.js
→
src/test/integration/zerostate
/zerostate
_po.js
浏览文件 @
70b03fc1
文件已移动
src/test/integration/zerostate_test.js
→
src/test/integration/zerostate
/zerostate
_test.js
浏览文件 @
70b03fc1
文件已移动
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录