Skip to content

Commit 7ed5ea6

Browse files
committed
Generic YAML editor for all resources (#807)
To test this edit a pod in a list. Missing things that will be done in next PR: * make the menu and popup look pretty * make json editor work on serve:prod (now images are missing)
1 parent 7a68617 commit 7ed5ea6

27 files changed

+790
-29
lines changed

bower.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"angular-resource": "~1.5.0",
1212
"angular-sanitize": "~1.5.0",
1313
"material-design-icons": "~2.2.2",
14-
"roboto-fontface": "~0.4.5"
14+
"roboto-fontface": "~0.4.5",
15+
"ng-jsoneditor": "angular-tools/ng-jsoneditor#~1.0.0"
1516
},
1617
"overrides": {
1718
"material-design-icons": {
@@ -21,7 +22,10 @@
2122
"main": "css/roboto-fontface.css"
2223
},
2324
"google-closure-library": {
24-
"main": ["closure/goog/base.js", "closure/goog/deps.js"]
25+
"main": [
26+
"closure/goog/base.js",
27+
"closure/goog/deps.js"
28+
]
2529
}
2630
},
2731
"devDependencies": {

build/build.js

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,27 @@ gulp.task('locales-for-backend:cross', ['clean-dist'], function() {
8888
* Builds production version of the frontend application for the default architecture
8989
* (one copy per locale) and plcaes it under .tmp/dist , preparing it for localization and revision.
9090
*/
91-
gulp.task('frontend-copies', ['fonts', 'icons', 'assets', 'index:prod', 'clean-dist'], function() {
92-
return createFrontendCopies([path.join(conf.paths.distPre, conf.arch.default, 'public')]);
93-
});
91+
gulp.task(
92+
'frontend-copies',
93+
['fonts', 'icons', 'assets', 'dependency-images', 'index:prod', 'clean-dist'], function() {
94+
return createFrontendCopies([path.join(conf.paths.distPre, conf.arch.default, 'public')]);
95+
});
9496

9597
/**
9698
* Builds production versions of the frontend application for all architecures
9799
* (one copy per locale) and places them under .tmp, preparing them for localization and revision.
98100
*/
99101
gulp.task(
100102
'frontend-copies:cross',
101-
['fonts:cross', 'icons:cross', 'assets:cross', 'index:prod', 'clean-dist'], function() {
103+
[
104+
'fonts:cross',
105+
'icons:cross',
106+
'assets:cross',
107+
'dependency-images:cross',
108+
'index:prod',
109+
'clean-dist',
110+
],
111+
function() {
102112
return createFrontendCopies(
103113
conf.arch.list.map((arch) => path.join(conf.paths.distPre, arch, 'public')));
104114
});
@@ -134,6 +144,20 @@ gulp.task('fonts', ['clean-dist'], function() { return fonts([conf.paths.distPub
134144
*/
135145
gulp.task('fonts:cross', ['clean-dist'], function() { return fonts(conf.paths.distPublicCross); });
136146

147+
/**
148+
* Copies images from dependencies to the dist directory for current architecture.
149+
*/
150+
gulp.task('dependency-images', ['clean-dist'], function() {
151+
return dependencyImages([conf.paths.distPublic]);
152+
});
153+
154+
/**
155+
* Copies images from dependencies to the dist directory for all architectures.
156+
*/
157+
gulp.task('dependency-images:cross', ['clean-dist'], function() {
158+
return dependencyImages(conf.paths.distPublicCross);
159+
});
160+
137161
/**
138162
* Cleans all build artifacts.
139163
*/
@@ -175,7 +199,13 @@ function createFrontendCopies(outputDirs) {
175199
return gulp.src(path.join(conf.paths.prodTmp, '*.html'))
176200
.pipe(gulpUseref({searchPath: searchPath}))
177201
.pipe(gulpIf('**/vendor.css', gulpMinifyCss()))
178-
.pipe(gulpIf('**/vendor.js', gulpUglify({preserveComments: uglifySaveLicense})))
202+
.pipe(gulpIf('**/vendor.js', gulpUglify({
203+
preserveComments: uglifySaveLicense,
204+
// Disable compression of unused vars. This speeds up minification a lot (like
205+
// 10 times).
206+
// See https://github.com/mishoo/UglifyJS2/issues/321
207+
compress: {unused: false},
208+
})))
179209
.pipe(gulpIf('*.html', gulpHtmlmin({
180210
removeComments: true,
181211
collapseWhitespace: true,
@@ -265,6 +295,18 @@ function fonts(outputDirs) {
265295
.pipe(multiDest(localizedOutputDirs));
266296
}
267297

298+
/**
299+
* Copies the font files to all dist directories per arch and locale.
300+
* @param {!Array<string>} outputDirs
301+
* @return {stream}
302+
*/
303+
function dependencyImages(outputDirs) {
304+
let localizedOutputDirs = createLocalizedOutputs(outputDirs, 'static/img');
305+
return gulp
306+
.src(path.join(conf.paths.jsoneditorImages, '*.png'), {base: conf.paths.jsoneditorImages})
307+
.pipe(multiDest(localizedOutputDirs));
308+
}
309+
268310
/**
269311
* Returns one subdirectory path for each supported locale inside all of the specified
270312
* outputDirs. Optionally, a subdirectory structure can be passed to append after each locale path.

build/conf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export default {
196196
hyperkube: path.join(basePath, 'build/hyperkube.sh'),
197197
i18nProd: path.join(basePath, '.tmp/i18n'),
198198
integrationTest: path.join(basePath, 'src/test/integration'),
199+
jsoneditorImages: path.join(basePath, 'bower_components/jsoneditor/src/css/img'),
199200
karmaConf: path.join(basePath, 'build/karma.conf.js'),
200201
materialIcons: path.join(basePath, 'bower_components/material-design-icons/iconfont'),
201202
nodeModules: path.join(basePath, 'node_modules'),

i18n/messages-en.xtb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,11 @@
155155
<translation id="3762856444030194375" key="MSG_PET_SET_INFO_STATUS_SECTION" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section name.">Status</translation>
156156
<translation id="1744330140020758003" key="MSG_PET_SET_INFO_PODS_ENTRY" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section pods entry.">Pods</translation>
157157
<translation id="6654869080140416303" key="MSG_PET_SET_INFO_PODS_STATUS_ENTRY" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section pods status entry.">Pods status</translation>
158+
<translation id="6480734540585386902" key="MSG_DELETE_RESOURCE_DIALOG_TITLE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Title for a delete resource dialog">Delete a <ph name="RESOURCE_KIND_NAME" /></translation>
159+
<translation id="1743501197722607271" key="MSG_DELETE_RESOURCE_DIALOG_CANCEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for cancel button">Cancel</translation>
160+
<translation id="1375098876763337363" key="MSG_DELETE_RESOURCE_DIALOG_DELETE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for delete button">Delete</translation>
161+
<translation id="7770496538218207073" key="MSG_EDIT_RESOURCE_DIALOG_TITLE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Title for a delete resource dialog">Edit a <ph name="RESOURCE_KIND_NAME" /></translation>
162+
<translation id="5059373780898524627" key="MSG_EDIT_RESOURCE_DIALOG_CANCEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for cancel button">Cancel</translation>
163+
<translation id="8463528551217463399" key="MSG_EDIT_RESOURCE_DIALOG_UPDATE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for update button">Update</translation>
164+
<translation id="6420130406957025720" key="MSG_YAML_EDIT_MENU_LABEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for YAML edit menu item.">View/edit JSON</translation>
158165
</translationbundle>

i18n/messages-ja.xtb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,11 @@
155155
<translation id="3762856444030194375" key="MSG_PET_SET_INFO_STATUS_SECTION" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section name.">Status</translation>
156156
<translation id="1744330140020758003" key="MSG_PET_SET_INFO_PODS_ENTRY" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section pods entry.">Pods</translation>
157157
<translation id="6654869080140416303" key="MSG_PET_SET_INFO_PODS_STATUS_ENTRY" source="/home/floreks/Projects/dashboard/.tmp/serve/app-dev.js" desc="Pet set info status section pods status entry.">Pods status</translation>
158+
<translation id="6480734540585386902" key="MSG_DELETE_RESOURCE_DIALOG_TITLE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Title for a delete resource dialog">Delete a <ph name="RESOURCE_KIND_NAME" /></translation>
159+
<translation id="1743501197722607271" key="MSG_DELETE_RESOURCE_DIALOG_CANCEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for cancel button">Cancel</translation>
160+
<translation id="1375098876763337363" key="MSG_DELETE_RESOURCE_DIALOG_DELETE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for delete button">Delete</translation>
161+
<translation id="7770496538218207073" key="MSG_EDIT_RESOURCE_DIALOG_TITLE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Title for a delete resource dialog">Edit a <ph name="RESOURCE_KIND_NAME" /></translation>
162+
<translation id="5059373780898524627" key="MSG_EDIT_RESOURCE_DIALOG_CANCEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for cancel button">Cancel</translation>
163+
<translation id="8463528551217463399" key="MSG_EDIT_RESOURCE_DIALOG_UPDATE" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for update button">Update</translation>
164+
<translation id="6420130406957025720" key="MSG_YAML_EDIT_MENU_LABEL" source="/usr/local/google/home/bryk/src/github.com/dashboard/.tmp/serve/app-dev.js" desc="Label for YAML edit menu item.">View/edit JSON</translation>
158165
</translationbundle>

src/app/backend/handler/apihandler.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
. "github.com/kubernetes/dashboard/validation"
4141
client "k8s.io/kubernetes/pkg/client/unversioned"
4242
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
43+
"k8s.io/kubernetes/pkg/runtime"
4344
)
4445

4546
const (
@@ -295,7 +296,12 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
295296
apiV1Ws.Route(
296297
apiV1Ws.DELETE("/{kind}/namespace/{namespace}/name/{name}").
297298
To(apiHandler.handleDeleteResource))
298-
299+
apiV1Ws.Route(
300+
apiV1Ws.GET("/{kind}/namespace/{namespace}/name/{name}").
301+
To(apiHandler.handleGetResource))
302+
apiV1Ws.Route(
303+
apiV1Ws.PUT("/{kind}/namespace/{namespace}/name/{name}").
304+
To(apiHandler.handlePutResource))
299305
return wsContainer
300306
}
301307

@@ -617,6 +623,40 @@ func (apiHandler *ApiHandler) handleDeleteReplicationController(
617623
response.WriteHeader(http.StatusOK)
618624
}
619625

626+
func (apiHandler *ApiHandler) handleGetResource(
627+
request *restful.Request, response *restful.Response) {
628+
kind := request.PathParameter("kind")
629+
namespace := request.PathParameter("namespace")
630+
name := request.PathParameter("name")
631+
632+
result, err := apiHandler.verber.Get(kind, namespace, name)
633+
if err != nil {
634+
handleInternalError(response, err)
635+
return
636+
}
637+
638+
response.WriteHeaderAndEntity(http.StatusCreated, result)
639+
}
640+
641+
func (apiHandler *ApiHandler) handlePutResource(
642+
request *restful.Request, response *restful.Response) {
643+
kind := request.PathParameter("kind")
644+
namespace := request.PathParameter("namespace")
645+
name := request.PathParameter("name")
646+
putSpec := &runtime.Unknown{}
647+
if err := request.ReadEntity(putSpec); err != nil {
648+
handleInternalError(response, err)
649+
return
650+
}
651+
652+
if err := apiHandler.verber.Put(kind, namespace, name, putSpec); err != nil {
653+
handleInternalError(response, err)
654+
return
655+
}
656+
657+
response.WriteHeader(http.StatusOK)
658+
}
659+
620660
func (apiHandler *ApiHandler) handleDeleteResource(
621661
request *restful.Request, response *restful.Response) {
622662
kind := request.PathParameter("kind")

src/app/backend/resource/common/verber.go

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"fmt"
1919

2020
"k8s.io/kubernetes/pkg/client/restclient"
21+
"k8s.io/kubernetes/pkg/runtime"
2122
)
2223

2324
// ResourceVerber is a struct responsible for doing common verb operations on resources, like
@@ -29,9 +30,24 @@ type ResourceVerber struct {
2930
batchClient RESTClient
3031
}
3132

33+
func (verber *ResourceVerber) getRESTClientByType(clientType ClientType) RESTClient {
34+
switch clientType {
35+
case ClientTypeExtensionClient:
36+
return verber.extensionsClient
37+
case ClientTypeAppsClient:
38+
return verber.appsClient
39+
case ClientTypeBatchClient:
40+
return verber.batchClient
41+
default:
42+
return verber.client
43+
}
44+
}
45+
3246
// RESTClient is an interface for REST operations used in this file.
3347
type RESTClient interface {
3448
Delete() *restclient.Request
49+
Put() *restclient.Request
50+
Get() *restclient.Request
3551
}
3652

3753
// NewResourceVerber creates a new resource verber that uses the given client for performing
@@ -58,15 +74,42 @@ func (verber *ResourceVerber) Delete(kind string, namespace string, name string)
5874
Error()
5975
}
6076

61-
func (verber *ResourceVerber) getRESTClientByType(clientType ClientType) RESTClient {
62-
switch clientType {
63-
case ClientTypeExtensionClient:
64-
return verber.extensionsClient
65-
case ClientTypeAppsClient:
66-
return verber.appsClient
67-
case ClientTypeBatchClient:
68-
return verber.batchClient
69-
default:
70-
return verber.client
77+
// Put puts new resource version of the given kind in the given namespace with the given name.
78+
func (verber *ResourceVerber) Put(kind string, namespace string, name string,
79+
object runtime.Object) error {
80+
81+
resourceSpec, ok := kindToAPIMapping[kind]
82+
if !ok {
83+
return fmt.Errorf("Unknown resource kind: %s", kind)
84+
}
85+
86+
client := verber.getRESTClientByType(resourceSpec.ClientType)
87+
88+
return client.Put().
89+
Namespace(namespace).
90+
Resource(resourceSpec.Resource).
91+
Name(name).
92+
Body(object).
93+
Do().
94+
Error()
95+
}
96+
97+
// Get gets the resource of the given kind in the given namespace with the given name.
98+
func (verber *ResourceVerber) Get(kind string, namespace string, name string) (runtime.Object, error) {
99+
resourceSpec, ok := kindToAPIMapping[kind]
100+
if !ok {
101+
return nil, fmt.Errorf("Unknown resource kind: %s", kind)
71102
}
103+
104+
client := verber.getRESTClientByType(resourceSpec.ClientType)
105+
106+
result := &runtime.Unknown{}
107+
err := client.Get().
108+
Namespace(namespace).
109+
Resource(resourceSpec.Resource).
110+
Name(name).
111+
Do().
112+
Into(result)
113+
114+
return result, err
72115
}

src/app/frontend/common/components/resourcecard/resourcecard_module.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {resourceCardComponent} from './resourcecard_component';
1717
import {resourceCardListComponent} from './resourcecardlist_component';
1818
import {resourceCardMenuComponent} from './resourcecardmenu_component';
1919
import {resourceCardDeleteMenuItemComponent} from './resourcecarddeletemenuitem_component';
20+
import {resourceCardEditMenuItemComponent} from './resourcecardeditmenuitem_component';
2021
import {resourceCardColumnComponent} from './resourcecardcolumn_component';
2122
import {resourceCardColumnsComponent} from './resourcecardcolumns_component';
2223
import {resourceCardHeaderColumnComponent} from './resourcecardheadercolumn_component';
@@ -39,6 +40,7 @@ export default angular
3940
.component('kdResourceCardList', resourceCardListComponent)
4041
.component('kdResourceCardMenu', resourceCardMenuComponent)
4142
.component('kdResourceCardDeleteMenuItem', resourceCardDeleteMenuItemComponent)
43+
.component('kdResourceCardEditMenuItem', resourceCardEditMenuItemComponent)
4244
.component('kdResourceCardColumn', resourceCardColumnComponent)
4345
.component('kdResourceCardColumns', resourceCardColumnsComponent)
4446
.component('kdResourceCardHeaderColumn', resourceCardHeaderColumnComponent)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!--
2+
Copyright 2015 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<md-menu-item>
18+
<md-button ng-click="$ctrl.edit()">
19+
{{::$ctrl.i18n.MSG_YAML_EDIT_MENU_LABEL}}
20+
</md-button>
21+
</md-menu-item>

0 commit comments

Comments
 (0)