From 96e77b3ada2a055b781a6a5bcb1e129f0111ab1d Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Tue, 13 Mar 2018 09:06:38 +1000 Subject: [PATCH 01/20] fix(api): fix a regression with the HTTP handler (#1718) --- api/http/handler/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/http/handler/handler.go b/api/http/handler/handler.go index ac0cc7b9f..05eea9ef5 100644 --- a/api/http/handler/handler.go +++ b/api/http/handler/handler.go @@ -52,7 +52,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.StripPrefix("/api", h.DockerHubHandler).ServeHTTP(w, r) case strings.HasPrefix(r.URL.Path, "/api/endpoints"): switch { - case strings.Contains(r.URL.Path, "/docker"): + case strings.Contains(r.URL.Path, "/docker/"): http.StripPrefix("/api/endpoints", h.DockerHandler).ServeHTTP(w, r) case strings.Contains(r.URL.Path, "/stacks"): http.StripPrefix("/api/endpoints", h.StackHandler).ServeHTTP(w, r) From 66f29dd1038bfd921a8e1cb2f2a177ac86d5d132 Mon Sep 17 00:00:00 2001 From: "Herwono W. Wijaya" Date: Tue, 13 Mar 2018 12:36:53 +0700 Subject: [PATCH 02/20] style(app): upgrade to font awesome v5 --- .../configs-datatable/configsDatatable.html | 16 +++---- .../containerNetworksDatatable.html | 2 +- .../containersDatatable.html | 42 +++++++++---------- .../events-datatable/eventsDatatable.html | 12 +++--- .../images-datatable/imagesDatatable.html | 18 ++++---- .../networks-datatable/networksDatatable.html | 34 +++++++-------- .../nodeTasksDatatable.html | 20 ++++----- .../nodes-datatable/nodesDatatable.html | 30 ++++++------- .../nodes-ss-datatable/nodesSSDatatable.html | 26 ++++++------ .../secrets-datatable/secretsDatatable.html | 14 +++---- .../services-datatable/servicesDatatable.html | 38 ++++++++--------- .../tasks-datatable/tasksDatatable.html | 22 +++++----- .../volumes-datatable/volumesDatatable.html | 22 +++++----- .../dockerSidebarContent.html | 4 +- .../components/log-viewer/logViewer.html | 2 +- app/docker/views/configs/configs.html | 4 +- app/docker/views/configs/edit/config.html | 8 ++-- .../containers/console/containerconsole.html | 4 +- app/docker/views/containers/containers.html | 2 +- .../containers/create/createcontainer.html | 4 +- .../views/containers/edit/container.html | 16 +++---- .../containers/inspect/containerinspect.html | 2 +- .../containers/stats/containerstats.html | 6 +-- app/docker/views/dashboard/dashboard.html | 8 ++-- app/docker/views/engine/engine.html | 2 +- app/docker/views/events/events.html | 2 +- app/docker/views/images/build/buildimage.html | 2 +- app/docker/views/images/edit/image.html | 10 ++--- app/docker/views/images/images.html | 2 +- app/docker/views/networks/edit/network.html | 4 +- app/docker/views/networks/networks.html | 2 +- app/docker/views/nodes/edit/node.html | 2 +- app/docker/views/secrets/edit/secret.html | 4 +- app/docker/views/secrets/secrets.html | 2 +- .../views/services/create/createservice.html | 4 +- app/docker/views/services/edit/service.html | 8 ++-- app/docker/views/services/services.html | 2 +- app/docker/views/stacks/edit/stack.html | 4 +- app/docker/views/stacks/stacks.html | 2 +- app/docker/views/swarm/swarm.html | 6 +-- .../swarm/visualizer/swarmvisualizer.html | 6 +-- app/docker/views/tasks/edit/task.html | 2 +- app/docker/views/templates/templates.html | 14 +++---- app/docker/views/volumes/edit/volume.html | 2 +- app/docker/views/volumes/volumes.html | 2 +- .../storidgeClusterEventsDatatable.html | 16 +++---- .../storidgeNodesDatatable.html | 16 +++---- .../storidgeProfilesDatatable.html | 6 +-- .../storidge/views/cluster/cluster.html | 4 +- .../storidge/views/monitor/monitor.html | 8 ++-- .../storidge/views/profiles/profiles.html | 8 ++-- app/portainer/components/buttonSpinner.js | 2 +- .../endpointsDatatable.html | 10 ++--- .../registriesDatatable.html | 10 ++--- .../stackServicesDatatable.html | 22 +++++----- .../stacks-datatable/stacksDatatable.html | 10 ++--- .../teams-datatable/teamsDatatable.html | 6 +-- .../users-datatable/usersDatatable.html | 16 +++---- .../endpointSecurity/porEndpointSecurity.html | 14 +++---- app/portainer/components/header-content.js | 2 +- app/portainer/components/header-title.js | 2 +- app/portainer/views/about/about.html | 18 ++++---- app/portainer/views/auth/auth.html | 2 +- app/portainer/views/endpoints/endpoints.html | 2 +- .../views/init/endpoint/initEndpoint.html | 6 +-- .../views/registries/registries.html | 2 +- .../settingsAuthentication.html | 2 +- app/portainer/views/settings/settings.html | 2 +- app/portainer/views/teams/edit/team.html | 2 +- app/portainer/views/teams/teams.html | 2 +- app/portainer/views/users/edit/user.html | 2 +- app/portainer/views/users/users.html | 2 +- assets/css/app.css | 2 +- gruntfile.js | 11 ++++- package.json | 2 +- vendor.yml | 10 ++++- yarn.lock | 8 ++-- 77 files changed, 340 insertions(+), 327 deletions(-) diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index 96a2dcc76..9ca9d1adc 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -3,7 +3,7 @@
- {{ $ctrl.title }} + {{ $ctrl.title }}
@@ -14,7 +14,7 @@
diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index f9e82b812..15421a656 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -67,7 +67,7 @@
+ diff --git a/app/docker/views/volumes/volumes.html b/app/docker/views/volumes/volumes.html index 234797714..85b57a11c 100644 --- a/app/docker/views/volumes/volumes.html +++ b/app/docker/views/volumes/volumes.html @@ -1,7 +1,7 @@ - + Volumes diff --git a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html index 61800cb82..6ce9e3f1f 100644 --- a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html +++ b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html @@ -22,29 +22,29 @@ Date - - + + Category - - + + Module - - + + Content - - + + diff --git a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html index 7478e83d5..973b517d7 100644 --- a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html +++ b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html @@ -22,29 +22,29 @@ Name - - + + IP Address - - + + Role - - + + Status - - + + diff --git a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html index e2ab91dd0..642f69a03 100644 --- a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html +++ b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html @@ -14,7 +14,7 @@
diff --git a/app/extensions/storidge/views/monitor/monitor.html b/app/extensions/storidge/views/monitor/monitor.html index b4ce1bfc4..2101294ce 100644 --- a/app/extensions/storidge/views/monitor/monitor.html +++ b/app/extensions/storidge/views/monitor/monitor.html @@ -1,7 +1,7 @@ - + @@ -12,7 +12,7 @@
- +
@@ -45,7 +45,7 @@
- +
@@ -78,7 +78,7 @@
- +
diff --git a/app/extensions/storidge/views/profiles/profiles.html b/app/extensions/storidge/views/profiles/profiles.html index 5e5b054a8..d6a5dcfce 100644 --- a/app/extensions/storidge/views/profiles/profiles.html +++ b/app/extensions/storidge/views/profiles/profiles.html @@ -1,7 +1,7 @@ - + @@ -49,7 +49,7 @@
- +
Items per page: diff --git a/app/portainer/components/buttonSpinner.js b/app/portainer/components/buttonSpinner.js index ca82bf322..357f17bf2 100644 --- a/app/portainer/components/buttonSpinner.js +++ b/app/portainer/components/buttonSpinner.js @@ -6,7 +6,7 @@ angular.module('portainer.app') spinning: '=buttonSpinner' }, transclude: true, - template: ' ' + template: ' ' }; return directive; diff --git a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html index cee17d2eb..95dc16296 100644 --- a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html +++ b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html @@ -14,7 +14,7 @@
@@ -114,7 +114,7 @@ {{ $ctrl.formData.TLSKey.name }} - +
diff --git a/app/portainer/components/header-content.js b/app/portainer/components/header-content.js index cb9de8f6e..638e78d50 100644 --- a/app/portainer/components/header-content.js +++ b/app/portainer/components/header-content.js @@ -6,7 +6,7 @@ angular.module('portainer.app') link: function (scope, iElement, iAttrs) { scope.username = Authentication.getUserDetails().username; }, - template: '', + template: '', restrict: 'E' }; return directive; diff --git a/app/portainer/components/header-title.js b/app/portainer/components/header-title.js index 3b4f88665..073410de6 100644 --- a/app/portainer/components/header-title.js +++ b/app/portainer/components/header-title.js @@ -10,7 +10,7 @@ angular.module('portainer.app') scope.displayDonationHeader = StateManager.getState().application.displayDonationHeader; }, transclude: true, - template: '
{{title}} {{username}} Help support portainer
', + template: '
{{title}} {{username}} Help support portainer
', restrict: 'E' }; return directive; diff --git a/app/portainer/views/about/about.html b/app/portainer/views/about/about.html index 918c8532a..c200ab24a 100644 --- a/app/portainer/views/about/about.html +++ b/app/portainer/views/about/about.html @@ -28,23 +28,23 @@

Fund our work

Contribute

Spread the word

  • Talk to your friends and colleagues about how awesome Portainer is!
  • -
  • Follow us on Twitter
  • +
  • Follow us on Twitter

@@ -56,7 +56,7 @@
- +

@@ -69,15 +69,15 @@

Community support

Services

diff --git a/app/portainer/views/auth/auth.html b/app/portainer/views/auth/auth.html index f58276395..6cde5c633 100644 --- a/app/portainer/views/auth/auth.html +++ b/app/portainer/views/auth/auth.html @@ -28,7 +28,7 @@
- + {{ state.AuthenticationError }} diff --git a/app/portainer/views/endpoints/endpoints.html b/app/portainer/views/endpoints/endpoints.html index b27569673..7b6eb9205 100644 --- a/app/portainer/views/endpoints/endpoints.html +++ b/app/portainer/views/endpoints/endpoints.html @@ -1,7 +1,7 @@ - + Endpoint management diff --git a/app/portainer/views/init/endpoint/initEndpoint.html b/app/portainer/views/init/endpoint/initEndpoint.html index c526d2ec8..5849c9b27 100644 --- a/app/portainer/views/init/endpoint/initEndpoint.html +++ b/app/portainer/views/init/endpoint/initEndpoint.html @@ -148,7 +148,7 @@ {{ formValues.TLSCACert.name }} - +
@@ -162,7 +162,7 @@ {{ formValues.TLSCert.name }} - +
@@ -175,7 +175,7 @@ {{ formValues.TLSKey.name }} - +
diff --git a/app/portainer/views/registries/registries.html b/app/portainer/views/registries/registries.html index e432c300b..8c822d8ee 100644 --- a/app/portainer/views/registries/registries.html +++ b/app/portainer/views/registries/registries.html @@ -1,7 +1,7 @@ - + Registry management diff --git a/app/portainer/views/settings/authentication/settingsAuthentication.html b/app/portainer/views/settings/authentication/settingsAuthentication.html index 2d655dea3..ce5b6798d 100644 --- a/app/portainer/views/settings/authentication/settingsAuthentication.html +++ b/app/portainer/views/settings/authentication/settingsAuthentication.html @@ -162,7 +162,7 @@ {{ formValues.TLSCACert.name }} - +
diff --git a/app/portainer/views/settings/settings.html b/app/portainer/views/settings/settings.html index a12aa4f0c..ed1e5ba74 100644 --- a/app/portainer/views/settings/settings.html +++ b/app/portainer/views/settings/settings.html @@ -168,7 +168,7 @@ {{ label.name }} {{ label.value }} - + No filter available. diff --git a/app/portainer/views/teams/edit/team.html b/app/portainer/views/teams/edit/team.html index a2942b38e..f0b4ca3be 100644 --- a/app/portainer/views/teams/edit/team.html +++ b/app/portainer/views/teams/edit/team.html @@ -16,7 +16,7 @@ Name {{ team.Name }} - + diff --git a/app/portainer/views/teams/teams.html b/app/portainer/views/teams/teams.html index 6da96c691..66c4b6e54 100644 --- a/app/portainer/views/teams/teams.html +++ b/app/portainer/views/teams/teams.html @@ -1,7 +1,7 @@ - + Teams management diff --git a/app/portainer/views/users/edit/user.html b/app/portainer/views/users/edit/user.html index e8a417461..5c8ab61a6 100644 --- a/app/portainer/views/users/edit/user.html +++ b/app/portainer/views/users/edit/user.html @@ -16,7 +16,7 @@ {{ user.Username }} - + diff --git a/app/portainer/views/users/users.html b/app/portainer/views/users/users.html index b1801f1db..047721771 100644 --- a/app/portainer/views/users/users.html +++ b/app/portainer/views/users/users.html @@ -1,7 +1,7 @@ - + User management diff --git a/assets/css/app.css b/assets/css/app.css index 3df9b6f5b..f5ec6b79c 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -586,7 +586,7 @@ ul.sidebar .sidebar-list .sidebar-sublist a.active { .boxselector_wrapper input[type="radio"]:checked + label::after { color: #337ab7; - font-family: FontAwesome; + font-family: "Font Awesome 5 Free"; border: 2px solid #337ab7; content: "\f00c"; font-size: 16px; diff --git a/gruntfile.js b/gruntfile.js index c957b3eb7..15c1fd81e 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -159,7 +159,7 @@ gruntfile_cfg.copy = { assets: { files: [ {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'node_modules/bootstrap/fonts/'}, - {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'node_modules/font-awesome/fonts/'}, + {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,eot,svg}', expand: true, cwd: 'node_modules/@fortawesome/fontawesome-free-webfonts/webfonts/'}, {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'node_modules/rdash-ui/dist/fonts/'}, {dest: '<%= distdir %>/images/', src: '**', expand: true, cwd: 'assets/images/'}, {dest: '<%= distdir %>/ico', src: '**', expand: true, cwd: 'assets/ico'} @@ -235,7 +235,8 @@ gruntfile_cfg.replace = { options: { patterns: [ { match: 'ENVIRONMENT', replacement: '<%= grunt.config.get("environment") %>' }, - { match: 'CONFIG_GA_ID', replacement: '<%= pkg.config.GA_ID %>' } + { match: 'CONFIG_GA_ID', replacement: '<%= pkg.config.GA_ID %>' }, + { match: /..\/webfonts\//g, replacement: '../fonts/'} ] }, files: [ @@ -244,6 +245,12 @@ gruntfile_cfg.replace = { flatten: true, src: ['.tmp/concat/js/app.js'], dest: '.tmp/concat/js' + }, + { + expand: true, + flatten: true, + src: ['.tmp/concat/css/app.css'], + dest: '.tmp/concat/css' } ] } diff --git a/package.json b/package.json index babf2346a..bd35b3e5d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "node": ">= 0.8.4" }, "dependencies": { + "@fortawesome/fontawesome-free-webfonts": "^1.0.4", "@uirouter/angularjs": "~1.0.6", "angular": "~1.5.0", "angular-clipboard": "^1.6.2", @@ -45,7 +46,6 @@ "chart.js": "~2.6.0", "codemirror": "~5.30.0", "filesize": "~3.3.0", - "font-awesome": "~4.7.0", "isteven-angular-multiselect": "~4.0.0", "jquery": "^3.3.1", "js-yaml": "~3.10.0", diff --git a/vendor.yml b/vendor.yml index a38cb34a0..251050659 100644 --- a/vendor.yml +++ b/vendor.yml @@ -42,7 +42,10 @@ css: - node_modules/rdash-ui/dist/css/rdash.css - node_modules/isteven-angular-multiselect/isteven-multi-select.css - node_modules/ui-select/dist/select.css - - node_modules/font-awesome/css/font-awesome.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-brands.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-regular.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-solid.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fontawesome.css - node_modules/toastr/build/toastr.css - node_modules/xterm/dist/xterm.css - node_modules/angularjs-slider/dist/rzslider.css @@ -55,7 +58,10 @@ css: - node_modules/rdash-ui/dist/css/rdash.min.css - node_modules/isteven-angular-multiselect/isteven-multi-select.css - node_modules/ui-select/dist/select.min.css - - node_modules/font-awesome/css/font-awesome.min.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-brands.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-regular.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-solid.css + - node_modules/@fortawesome/fontawesome-free-webfonts/css/fontawesome.css - node_modules/toastr/build/toastr.min.css - node_modules/xterm/dist/xterm.css - node_modules/angularjs-slider/dist/rzslider.min.css diff --git a/yarn.lock b/yarn.lock index 0ecbadb85..e64420e5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"@fortawesome/fontawesome-free-webfonts@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free-webfonts/-/fontawesome-free-webfonts-1.0.4.tgz#bac5d89755bf3bc2d2b4deee47d92febf641bb1f" + "@uirouter/angularjs@~1.0.6": version "1.0.11" resolved "https://registry.yarnpkg.com/@uirouter/angularjs/-/angularjs-1.0.11.tgz#ced1ec8bea68a5db7dcfd77a43b7b8b9a2953540" @@ -1482,10 +1486,6 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -font-awesome@~4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133" - for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" From d34b1d5f9deab4a29f6c1723cd55c14ecce043b9 Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Tue, 13 Mar 2018 21:09:02 +1000 Subject: [PATCH 03/20] fix(build-system): fix task order after fontawesome5 integration (#1724) --- gruntfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gruntfile.js b/gruntfile.js index 15c1fd81e..05ed1323f 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -16,9 +16,9 @@ module.exports = function (grunt) { 'html2js', 'useminPrepare:release', 'concat', - 'postcss:build', 'clean:tmpl', 'replace', + 'postcss:build', 'uglify' ]); grunt.registerTask('after-copy', [ @@ -218,7 +218,7 @@ gruntfile_cfg.postcss = { cssnano() // minify the result ] }, - src: '<%= distdir %>/css/<%= pkg.name %>.css', + src: '.tmp/concat/css/app.css', dest: '<%= distdir %>/css/app.css' } }; From 706490db5e37b6303489dba838c9fce56fc668cc Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Tue, 13 Mar 2018 21:35:12 +1000 Subject: [PATCH 04/20] fix(api): use EntryPoint as a reference to overwrite stack Compose file (#1725) --- api/filesystem/filesystem.go | 8 ++++---- api/http/handler/stack.go | 6 +++--- api/portainer.go | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/filesystem/filesystem.go b/api/filesystem/filesystem.go index 236845410..26eff582d 100644 --- a/api/filesystem/filesystem.go +++ b/api/filesystem/filesystem.go @@ -76,14 +76,14 @@ func (service *Service) GetStackProjectPath(stackIdentifier string) string { // StoreStackFileFromString creates a subfolder in the ComposeStorePath and stores a new file using the content from a string. // It returns the path to the folder where the file is stored. -func (service *Service) StoreStackFileFromString(stackIdentifier, stackFileContent string) (string, error) { +func (service *Service) StoreStackFileFromString(stackIdentifier, fileName, stackFileContent string) (string, error) { stackStorePath := path.Join(ComposeStorePath, stackIdentifier) err := service.createDirectoryInStoreIfNotExist(stackStorePath) if err != nil { return "", err } - composeFilePath := path.Join(stackStorePath, ComposeFileDefaultName) + composeFilePath := path.Join(stackStorePath, fileName) data := []byte(stackFileContent) r := bytes.NewReader(data) @@ -97,14 +97,14 @@ func (service *Service) StoreStackFileFromString(stackIdentifier, stackFileConte // StoreStackFileFromReader creates a subfolder in the ComposeStorePath and stores a new file using the content from an io.Reader. // It returns the path to the folder where the file is stored. -func (service *Service) StoreStackFileFromReader(stackIdentifier string, r io.Reader) (string, error) { +func (service *Service) StoreStackFileFromReader(stackIdentifier, fileName string, r io.Reader) (string, error) { stackStorePath := path.Join(ComposeStorePath, stackIdentifier) err := service.createDirectoryInStoreIfNotExist(stackStorePath) if err != nil { return "", err } - composeFilePath := path.Join(stackStorePath, ComposeFileDefaultName) + composeFilePath := path.Join(stackStorePath, fileName) err = service.createFileInStore(composeFilePath, r) if err != nil { diff --git a/api/http/handler/stack.go b/api/http/handler/stack.go index 86b597e40..ff872896d 100644 --- a/api/http/handler/stack.go +++ b/api/http/handler/stack.go @@ -179,7 +179,7 @@ func (handler *StackHandler) handlePostStacksStringMethod(w http.ResponseWriter, Env: req.Env, } - projectPath, err := handler.FileService.StoreStackFileFromString(string(stack.ID), stackFileContent) + projectPath, err := handler.FileService.StoreStackFileFromString(string(stack.ID), stack.EntryPoint, stackFileContent) if err != nil { httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) return @@ -431,7 +431,7 @@ func (handler *StackHandler) handlePostStacksFileMethod(w http.ResponseWriter, r Env: env, } - projectPath, err := handler.FileService.StoreStackFileFromReader(string(stack.ID), stackFile) + projectPath, err := handler.FileService.StoreStackFileFromReader(string(stack.ID), stack.EntryPoint, stackFile) if err != nil { httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) return @@ -631,7 +631,7 @@ func (handler *StackHandler) handlePutStack(w http.ResponseWriter, r *http.Reque } stack.Env = req.Env - _, err = handler.FileService.StoreStackFileFromString(string(stack.ID), req.StackFileContent) + _, err = handler.FileService.StoreStackFileFromString(string(stack.ID), stack.EntryPoint, req.StackFileContent) if err != nil { httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) return diff --git a/api/portainer.go b/api/portainer.go index f001f83df..8c60b9973 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -369,8 +369,8 @@ type ( DeleteTLSFile(folder string, fileType TLSFileType) error DeleteTLSFiles(folder string) error GetStackProjectPath(stackIdentifier string) string - StoreStackFileFromString(stackIdentifier string, stackFileContent string) (string, error) - StoreStackFileFromReader(stackIdentifier string, r io.Reader) (string, error) + StoreStackFileFromString(stackIdentifier, fileName, stackFileContent string) (string, error) + StoreStackFileFromReader(stackIdentifier, fileName string, r io.Reader) (string, error) } // GitService represents a service for managing Git. From 9e47aedbe6338493b84f39174af6de61aaa2d8b8 Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Wed, 14 Mar 2018 09:47:21 +1000 Subject: [PATCH 05/20] fix(api): ignore directory existence check and use os.MkdirAll (#1719) --- api/filesystem/filesystem.go | 43 +++++++++++------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/api/filesystem/filesystem.go b/api/filesystem/filesystem.go index 26eff582d..1f59fd0c8 100644 --- a/api/filesystem/filesystem.go +++ b/api/filesystem/filesystem.go @@ -42,20 +42,17 @@ func NewService(dataStorePath, fileStorePath string) (*Service, error) { fileStorePath: path.Join(dataStorePath, fileStorePath), } - // Checking if a mount directory exists is broken with Go on Windows. - // This will need to be reviewed after the issue has been fixed in Go. - // See: https://github.com/portainer/portainer/issues/474 - // err := createDirectoryIfNotExist(dataStorePath, 0755) - // if err != nil { - // return nil, err - // } - - err := service.createDirectoryInStoreIfNotExist(TLSStorePath) + err := os.MkdirAll(dataStorePath, 0755) if err != nil { return nil, err } - err = service.createDirectoryInStoreIfNotExist(ComposeStorePath) + err = service.createDirectoryInStore(TLSStorePath) + if err != nil { + return nil, err + } + + err = service.createDirectoryInStore(ComposeStorePath) if err != nil { return nil, err } @@ -78,7 +75,7 @@ func (service *Service) GetStackProjectPath(stackIdentifier string) string { // It returns the path to the folder where the file is stored. func (service *Service) StoreStackFileFromString(stackIdentifier, fileName, stackFileContent string) (string, error) { stackStorePath := path.Join(ComposeStorePath, stackIdentifier) - err := service.createDirectoryInStoreIfNotExist(stackStorePath) + err := service.createDirectoryInStore(stackStorePath) if err != nil { return "", err } @@ -99,7 +96,7 @@ func (service *Service) StoreStackFileFromString(stackIdentifier, fileName, stac // It returns the path to the folder where the file is stored. func (service *Service) StoreStackFileFromReader(stackIdentifier, fileName string, r io.Reader) (string, error) { stackStorePath := path.Join(ComposeStorePath, stackIdentifier) - err := service.createDirectoryInStoreIfNotExist(stackStorePath) + err := service.createDirectoryInStore(stackStorePath) if err != nil { return "", err } @@ -117,7 +114,7 @@ func (service *Service) StoreStackFileFromReader(stackIdentifier, fileName strin // StoreTLSFile creates a folder in the TLSStorePath and stores a new file with the content from r. func (service *Service) StoreTLSFile(folder string, fileType portainer.TLSFileType, r io.Reader) error { storePath := path.Join(TLSStorePath, folder) - err := service.createDirectoryInStoreIfNotExist(storePath) + err := service.createDirectoryInStore(storePath) if err != nil { return err } @@ -201,24 +198,10 @@ func (service *Service) GetFileContent(filePath string) (string, error) { return string(content), nil } -// createDirectoryInStoreIfNotExist creates a new directory in the file store if it doesn't exists on the file system. -func (service *Service) createDirectoryInStoreIfNotExist(name string) error { +// createDirectoryInStore creates a new directory in the file store +func (service *Service) createDirectoryInStore(name string) error { path := path.Join(service.fileStorePath, name) - return createDirectoryIfNotExist(path, 0700) -} - -// createDirectoryIfNotExist creates a directory if it doesn't exists on the file system. -func createDirectoryIfNotExist(path string, mode uint32) error { - _, err := os.Stat(path) - if os.IsNotExist(err) { - err = os.Mkdir(path, os.FileMode(mode)) - if err != nil { - return err - } - } else if err != nil { - return err - } - return nil + return os.MkdirAll(path, 0700) } // createFile creates a new file in the file store with the content from r. From f0621cb09cfbf8cfd2c2f367e1b36b4f034c6806 Mon Sep 17 00:00:00 2001 From: 1138-4EB <1138-4EB@users.noreply.github.com> Date: Wed, 14 Mar 2018 01:24:00 +0100 Subject: [PATCH 06/20] chore(build-system): use regular vendor files, ignore (pre)minified (#1475) --- gruntfile.js | 13 ++--- vendor.yml | 159 +++++++++++++++++---------------------------------- 2 files changed, 57 insertions(+), 115 deletions(-) diff --git a/gruntfile.js b/gruntfile.js index 05ed1323f..145789cf4 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -12,7 +12,7 @@ module.exports = function (grunt) { grunt.registerTask('default', ['eslint', 'build']); grunt.registerTask('before-copy', [ - 'vendor:', + 'vendor', 'html2js', 'useminPrepare:release', 'concat', @@ -38,7 +38,7 @@ module.exports = function (grunt) { 'clean:app', 'shell:buildBinary:linux:' + arch, 'shell:downloadDockerBinary:linux:' + arch, - 'vendor:regular', + 'vendor', 'html2js', 'useminPrepare:dev', 'concat', @@ -55,20 +55,19 @@ module.exports = function (grunt) { grunt.registerTask('clear', ['clean:app']); // Load content of `vendor.yml` to src.jsVendor, src.cssVendor and src.angularVendor - grunt.registerTask('vendor', 'vendor:', function(min) { - // Argument `min` defaults to 'minified' - var minification = (min === '') ? 'minified' : min; + grunt.registerTask('vendor', function() { var vendorFile = grunt.file.readYAML('vendor.yml'); for (var filelist in vendorFile) { if (vendorFile.hasOwnProperty(filelist)) { - var list = vendorFile[filelist][minification]; + var list = vendorFile[filelist]; // Check if any of the files is missing for (var itemIndex in list) { if (list.hasOwnProperty(itemIndex)) { - var item = list[itemIndex]; + var item = 'node_modules/'+list[itemIndex]; if (!grunt.file.exists(item)) { grunt.fail.warn('Dependency file ' + item + ' not found.'); } + list[itemIndex] = item; } } // If none is missing, save the list diff --git a/vendor.yml b/vendor.yml index 251050659..a8c35ec02 100644 --- a/vendor.yml +++ b/vendor.yml @@ -1,112 +1,55 @@ --- js: - regular: - - node_modules/jquery/dist/jquery.js - - node_modules/bootstrap/dist/js/bootstrap.js - - node_modules/bootbox/bootbox.js - - node_modules/filesize/lib/filesize.js - - node_modules/lodash/lodash.js - - node_modules/moment/moment.js - - node_modules/chart.js/dist/Chart.js - - node_modules/splitargs/src/splitargs.js - - node_modules/toastr/toastr.js - - node_modules/xterm/dist/xterm.js - - node_modules/xterm/dist/addons/fit/fit.js - - node_modules/js-yaml/dist/js-yaml.js - - node_modules/codemirror/lib/codemirror.js - - node_modules/codemirror/mode/yaml/yaml.js - - node_modules/codemirror/addon/lint/lint.js - - node_modules/codemirror/addon/lint/yaml-lint.js - - node_modules/codemirror/addon/display/placeholder.js - minified: - - node_modules/jquery/dist/jquery.min.js - - node_modules/bootstrap/dist/js/bootstrap.min.js - - node_modules/bootbox/bootbox.js - - node_modules/filesize/lib/filesize.js - - node_modules/lodash/lodash.min.js - - node_modules/moment/min/moment.min.js - - node_modules/chart.js/dist/Chart.min.js - - node_modules/splitargs/src/splitargs.js - - node_modules/toastr/build/toastr.min.js - - node_modules/xterm/dist/xterm.js - - node_modules/xterm/dist/addons/fit/fit.js - - node_modules/js-yaml/dist/js-yaml.min.js - - node_modules/codemirror/lib/codemirror.js - - node_modules/codemirror/mode/yaml/yaml.js - - node_modules/codemirror/addon/lint/lint.js - - node_modules/codemirror/addon/lint/yaml-lint.js - - node_modules/codemirror/addon/display/placeholder.js + - 'jquery/dist/jquery.js' + - 'bootstrap/dist/js/bootstrap.js' + - 'bootbox/bootbox.js' + - 'filesize/lib/filesize.js' + - 'lodash/lodash.js' + - 'moment/moment.js' + - 'chart.js/dist/Chart.js' + - 'splitargs/src/splitargs.js' + - 'toastr/toastr.js' + - 'xterm/dist/xterm.js' + - 'xterm/dist/addons/fit/fit.js' + - 'js-yaml/dist/js-yaml.js' + - 'codemirror/lib/codemirror.js' + - 'codemirror/mode/yaml/yaml.js' + - 'codemirror/addon/lint/lint.js' + - 'codemirror/addon/lint/yaml-lint.js' + - 'codemirror/addon/display/placeholder.js' css: - regular: - - node_modules/bootstrap/dist/css/bootstrap.css - - node_modules/rdash-ui/dist/css/rdash.css - - node_modules/isteven-angular-multiselect/isteven-multi-select.css - - node_modules/ui-select/dist/select.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-brands.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-regular.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-solid.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fontawesome.css - - node_modules/toastr/build/toastr.css - - node_modules/xterm/dist/xterm.css - - node_modules/angularjs-slider/dist/rzslider.css - - node_modules/codemirror/lib/codemirror.css - - node_modules/codemirror/addon/lint/lint.css - - node_modules/angular-json-tree/dist/angular-json-tree.css - - node_modules/angular-loading-bar/build/loading-bar.css - minified: - - node_modules/bootstrap/dist/css/bootstrap.min.css - - node_modules/rdash-ui/dist/css/rdash.min.css - - node_modules/isteven-angular-multiselect/isteven-multi-select.css - - node_modules/ui-select/dist/select.min.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-brands.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-regular.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fa-solid.css - - node_modules/@fortawesome/fontawesome-free-webfonts/css/fontawesome.css - - node_modules/toastr/build/toastr.min.css - - node_modules/xterm/dist/xterm.css - - node_modules/angularjs-slider/dist/rzslider.min.css - - node_modules/codemirror/lib/codemirror.css - - node_modules/codemirror/addon/lint/lint.css - - node_modules/angular-json-tree/dist/angular-json-tree.css - - node_modules/angular-loading-bar/build/loading-bar.min.css + - 'bootstrap/dist/css/bootstrap.css' + - 'rdash-ui/dist/css/rdash.css' + - 'isteven-angular-multiselect/isteven-multi-select.css' + - 'ui-select/dist/select.css' + - '@fortawesome/fontawesome-free-webfonts/css/fa-brands.css' + - '@fortawesome/fontawesome-free-webfonts/css/fa-regular.css' + - '@fortawesome/fontawesome-free-webfonts/css/fa-solid.css' + - '@fortawesome/fontawesome-free-webfonts/css/fontawesome.css' + - 'toastr/build/toastr.css' + - 'xterm/dist/xterm.css' + - 'angularjs-slider/dist/rzslider.css' + - 'codemirror/lib/codemirror.css' + - 'codemirror/addon/lint/lint.css' + - 'angular-json-tree/dist/angular-json-tree.css' + - 'angular-loading-bar/build/loading-bar.css' angular: - regular: - - node_modules/angular/angular.js - - node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js - - node_modules/angular-cookies/angular-cookies.js - - node_modules/angular-google-analytics/dist/angular-google-analytics.js - - node_modules/angular-jwt/dist/angular-jwt.js - - node_modules/angular-local-storage/dist/angular-local-storage.js - - node_modules/angular-messages/angular-messages.js - - node_modules/angular-resource/angular-resource.js - - node_modules/angular-sanitize/angular-sanitize.js - - node_modules/ui-select/dist/select.js - - node_modules/@uirouter/angularjs/release/angular-ui-router.js - - node_modules/angular-utils-pagination/dirPagination.js - - node_modules/ng-file-upload/dist/ng-file-upload.js - - node_modules/angularjs-slider/dist/rzslider.js - - node_modules/isteven-angular-multiselect/isteven-multi-select.js - - node_modules/angular-json-tree/dist/angular-json-tree.js - - node_modules/angular-loading-bar/build/loading-bar.js - - node_modules/angularjs-scroll-glue/src/scrollglue.js - - node_modules/angular-clipboard/angular-clipboard.js - minified: - - node_modules/angular/angular.min.js - - node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js - - node_modules/angular-cookies/angular-cookies.min.js - - node_modules/angular-google-analytics/dist/angular-google-analytics.min.js - - node_modules/angular-jwt/dist/angular-jwt.min.js - - node_modules/angular-local-storage/dist/angular-local-storage.min.js - - node_modules/angular-messages/angular-messages.min.js - - node_modules/angular-resource/angular-resource.min.js - - node_modules/angular-sanitize/angular-sanitize.min.js - - node_modules/ui-select/dist/select.min.js - - node_modules/@uirouter/angularjs/release/angular-ui-router.min.js - - node_modules/angular-utils-pagination/dirPagination.js - - node_modules/ng-file-upload/dist/ng-file-upload.min.js - - node_modules/angularjs-slider/dist/rzslider.min.js - - node_modules/isteven-angular-multiselect/isteven-multi-select.js - - node_modules/angular-json-tree/dist/angular-json-tree.min.js - - node_modules/angular-loading-bar/build/loading-bar.min.js - - node_modules/angularjs-scroll-glue/src/scrollglue.js - - node_modules/angular-clipboard/angular-clipboard.js + - 'angular/angular.js' + - 'angular-ui-bootstrap/dist/ui-bootstrap-tpls.js' + - 'angular-cookies/angular-cookies.js' + - 'angular-google-analytics/dist/angular-google-analytics.js' + - 'angular-jwt/dist/angular-jwt.js' + - 'angular-local-storage/dist/angular-local-storage.js' + - 'angular-messages/angular-messages.js' + - 'angular-resource/angular-resource.js' + - 'angular-sanitize/angular-sanitize.js' + - 'ui-select/dist/select.js' + - '@uirouter/angularjs/release/angular-ui-router.js' + - 'angular-utils-pagination/dirPagination.js' + - 'ng-file-upload/dist/ng-file-upload.js' + - 'angularjs-slider/dist/rzslider.js' + - 'isteven-angular-multiselect/isteven-multi-select.js' + - 'angular-json-tree/dist/angular-json-tree.js' + - 'angular-loading-bar/build/loading-bar.js' + - 'angularjs-scroll-glue/src/scrollglue.js' + - 'angular-clipboard/angular-clipboard.js' From 4e38e4ba33e3d9f2883a03dddd1835d219d71525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kozio=C5=82?= Date: Wed, 14 Mar 2018 01:27:06 +0100 Subject: [PATCH 07/20] feat(image-details): display image layer order and sort by it by default (#1715) * feat(image-details): display image layer depth and sort by it by default (#1706) * refactor(image-details): rename 'Depth' to 'Order' in image layers table * refactor(image-details): sort image layers from the bottom to the top one --- app/docker/models/imageLayer.js | 3 ++- app/docker/services/imageService.js | 4 +++- app/docker/views/images/edit/image.html | 10 ++++++++++ app/docker/views/images/edit/imageController.js | 4 ++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/docker/models/imageLayer.js b/app/docker/models/imageLayer.js index 59889d290..15d79b785 100644 --- a/app/docker/models/imageLayer.js +++ b/app/docker/models/imageLayer.js @@ -1,4 +1,5 @@ -function ImageLayerViewModel(data) { +function ImageLayerViewModel(order, data) { + this.Order = order; this.Id = data.Id; this.Created = data.Created; this.CreatedBy = data.CreatedBy; diff --git a/app/docker/services/imageService.js b/app/docker/services/imageService.js index 973014ca7..112536cca 100644 --- a/app/docker/services/imageService.js +++ b/app/docker/services/imageService.js @@ -57,8 +57,10 @@ angular.module('portainer.docker') deferred.reject({ msg: data.message }); } else { var layers = []; + var order = data.length; angular.forEach(data, function(imageLayer) { - layers.push(new ImageLayerViewModel(imageLayer)); + layers.push(new ImageLayerViewModel(order, imageLayer)); + order--; }); deferred.resolve(layers); } diff --git a/app/docker/views/images/edit/image.html b/app/docker/views/images/edit/image.html index 43f1f867c..f07275216 100644 --- a/app/docker/views/images/edit/image.html +++ b/app/docker/views/images/edit/image.html @@ -182,6 +182,13 @@ + + diff --git a/app/docker/views/images/edit/imageController.js b/app/docker/views/images/edit/imageController.js index b2470a4de..2e59fe912 100644 --- a/app/docker/views/images/edit/imageController.js +++ b/app/docker/views/images/edit/imageController.js @@ -6,8 +6,8 @@ function ($q, $scope, $transition$, $state, $timeout, ImageService, RegistryServ Registry: '' }; - $scope.sortType = 'Size'; - $scope.sortReverse = true; + $scope.sortType = 'Order'; + $scope.sortReverse = false; $scope.order = function(sortType) { $scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false; From 50ece68f350a8a0dd16ea850571162f52c9c9e78 Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Wed, 14 Mar 2018 15:32:14 +1000 Subject: [PATCH 08/20] style(app): update icon style (#1727) --- .../datatables/configs-datatable/configsDatatable.html | 2 +- .../containers-datatable/containersDatatable.html | 2 +- .../datatables/nodes-datatable/nodesDatatable.html | 2 +- .../datatables/services-datatable/servicesDatatable.html | 2 +- .../datatables/tasks-datatable/tasksDatatable.html | 2 +- .../dockerSidebarContent/dockerSidebarContent.html | 2 +- app/docker/views/containers/edit/container.html | 6 +++--- app/docker/views/containers/inspect/containerinspect.html | 2 +- app/docker/views/images/build/buildimage.html | 2 +- app/docker/views/images/edit/image.html | 4 ++-- app/docker/views/services/edit/service.html | 2 +- app/docker/views/stacks/create/createstack.html | 2 +- app/docker/views/tasks/edit/task.html | 2 +- .../datatables/users-datatable/usersDatatable.html | 2 +- app/portainer/components/header-title.js | 2 +- app/portainer/views/about/about.html | 4 ++-- vendor.yml | 1 - 17 files changed, 20 insertions(+), 21 deletions(-) diff --git a/app/docker/components/datatables/configs-datatable/configsDatatable.html b/app/docker/components/datatables/configs-datatable/configsDatatable.html index 9ca9d1adc..f41830f44 100644 --- a/app/docker/components/datatables/configs-datatable/configsDatatable.html +++ b/app/docker/components/datatables/configs-datatable/configsDatatable.html @@ -3,7 +3,7 @@
- {{ $ctrl.title }} + {{ $ctrl.title }}
diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index 15421a656..973c1c5e6 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -196,7 +196,7 @@
diff --git a/app/docker/components/dockerSidebarContent/dockerSidebarContent.html b/app/docker/components/dockerSidebarContent/dockerSidebarContent.html index 2cecd1aaf..ba0001c9c 100644 --- a/app/docker/components/dockerSidebarContent/dockerSidebarContent.html +++ b/app/docker/components/dockerSidebarContent/dockerSidebarContent.html @@ -26,7 +26,7 @@ Volumes - +
+ + Order + + + + Size @@ -199,6 +206,9 @@
+ {{ layer.Order }} + {{ layer.Size | humansize }}
- +
diff --git a/app/docker/components/datatables/nodes-datatable/nodesDatatable.html b/app/docker/components/datatables/nodes-datatable/nodesDatatable.html index 987a6bc2e..ab825e5fa 100644 --- a/app/docker/components/datatables/nodes-datatable/nodesDatatable.html +++ b/app/docker/components/datatables/nodes-datatable/nodesDatatable.html @@ -3,7 +3,7 @@
- {{ $ctrl.title }} + {{ $ctrl.title }}
diff --git a/app/docker/components/datatables/services-datatable/servicesDatatable.html b/app/docker/components/datatables/services-datatable/servicesDatatable.html index cfebcf140..04584de28 100644 --- a/app/docker/components/datatables/services-datatable/servicesDatatable.html +++ b/app/docker/components/datatables/services-datatable/servicesDatatable.html @@ -110,7 +110,7 @@ - +
diff --git a/app/docker/components/datatables/tasks-datatable/tasksDatatable.html b/app/docker/components/datatables/tasks-datatable/tasksDatatable.html index f596bcd0e..e1ba5886a 100644 --- a/app/docker/components/datatables/tasks-datatable/tasksDatatable.html +++ b/app/docker/components/datatables/tasks-datatable/tasksDatatable.html @@ -66,7 +66,7 @@ {{ item.Updated | getisodate }} - View logs + View logs
diff --git a/app/docker/views/containers/inspect/containerinspect.html b/app/docker/views/containers/inspect/containerinspect.html index 16cdd503a..2289eeb4a 100644 --- a/app/docker/views/containers/inspect/containerinspect.html +++ b/app/docker/views/containers/inspect/containerinspect.html @@ -12,7 +12,7 @@ - + diff --git a/app/docker/views/images/build/buildimage.html b/app/docker/views/images/build/buildimage.html index 73428599e..53e00acd9 100644 --- a/app/docker/views/images/build/buildimage.html +++ b/app/docker/views/images/build/buildimage.html @@ -217,7 +217,7 @@ - Output + Output
               

{{ line }}

diff --git a/app/docker/views/images/edit/image.html b/app/docker/views/images/edit/image.html index f07275216..1cc50a61b 100644 --- a/app/docker/views/images/edit/image.html +++ b/app/docker/views/images/edit/image.html @@ -24,7 +24,7 @@ - + @@ -36,7 +36,7 @@ Note: you can click on the upload icon to push an image or on the download icon to pull an image - or on the trash icon to delete a tag. + or on the trash icon to delete a tag.
diff --git a/app/docker/views/services/edit/service.html b/app/docker/views/services/edit/service.html index 0d7e8a1b8..6669f53a4 100644 --- a/app/docker/views/services/edit/service.html +++ b/app/docker/views/services/edit/service.html @@ -73,7 +73,7 @@
- Service logs + Service logs {{ task.Status.ContainerStatus.ContainerID }}
Task logsTask logs
diff --git a/app/portainer/components/datatables/users-datatable/usersDatatable.html b/app/portainer/components/datatables/users-datatable/usersDatatable.html index 5db9e58d1..605d6380c 100644 --- a/app/portainer/components/datatables/users-datatable/usersDatatable.html +++ b/app/portainer/components/datatables/users-datatable/usersDatatable.html @@ -63,7 +63,7 @@ - + {{ item.RoleName }} diff --git a/app/portainer/components/header-title.js b/app/portainer/components/header-title.js index 073410de6..92a6e3d4c 100644 --- a/app/portainer/components/header-title.js +++ b/app/portainer/components/header-title.js @@ -10,7 +10,7 @@ angular.module('portainer.app') scope.displayDonationHeader = StateManager.getState().application.displayDonationHeader; }, transclude: true, - template: '
{{title}} {{username}} Help support portainer
', + template: '
{{title}} {{username}} Help support portainer
', restrict: 'E' }; return directive; diff --git a/app/portainer/views/about/about.html b/app/portainer/views/about/about.html index c200ab24a..b1af972a3 100644 --- a/app/portainer/views/about/about.html +++ b/app/portainer/views/about/about.html @@ -28,7 +28,7 @@

Fund our work

@@ -77,7 +77,7 @@ Services

diff --git a/vendor.yml b/vendor.yml index a8c35ec02..5234104ce 100644 --- a/vendor.yml +++ b/vendor.yml @@ -23,7 +23,6 @@ css: - 'isteven-angular-multiselect/isteven-multi-select.css' - 'ui-select/dist/select.css' - '@fortawesome/fontawesome-free-webfonts/css/fa-brands.css' - - '@fortawesome/fontawesome-free-webfonts/css/fa-regular.css' - '@fortawesome/fontawesome-free-webfonts/css/fa-solid.css' - '@fortawesome/fontawesome-free-webfonts/css/fontawesome.css' - 'toastr/build/toastr.css' From adf1ba7b473994d12397a4c9ffc059ff409b6b5d Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Fri, 16 Mar 2018 07:22:05 +1000 Subject: [PATCH 09/20] feat(stack-creation): add the ability to specify git credentials (#1722) * feat(stack-creation): add the ability to specify git credentials * docs(api): update Swagger --- api/git/git.go | 24 +++++++++--- api/http/handler/stack.go | 37 ++++++++++--------- api/portainer.go | 3 +- api/swagger.yaml | 18 +++++++-- app/docker/services/stackService.js | 9 +++-- .../stacks/create/createStackController.js | 32 +++++++++------- .../views/stacks/create/createstack.html | 28 ++++++++++++-- 7 files changed, 106 insertions(+), 45 deletions(-) diff --git a/api/git/git.go b/api/git/git.go index 8758363b9..5e58363c7 100644 --- a/api/git/git.go +++ b/api/git/git.go @@ -1,6 +1,9 @@ package git import ( + "net/url" + "strings" + "gopkg.in/src-d/go-git.v4" ) @@ -14,12 +17,23 @@ func NewService(dataStorePath string) (*Service, error) { return service, nil } -// CloneRepository clones a git repository using the specified URL in the specified +// ClonePublicRepository clones a public git repository using the specified URL in the specified // destination folder. -func (service *Service) CloneRepository(url, destination string) error { - _, err := git.PlainClone(destination, false, &git.CloneOptions{ - URL: url, - }) +func (service *Service) ClonePublicRepository(repositoryURL, destination string) error { + return cloneRepository(repositoryURL, destination) +} +// ClonePrivateRepositoryWithBasicAuth clones a private git repository using the specified URL in the specified +// destination folder. It will use the specified username and password for basic HTTP authentication. +func (service *Service) ClonePrivateRepositoryWithBasicAuth(repositoryURL, destination, username, password string) error { + credentials := username + ":" + url.PathEscape(password) + repositoryURL = strings.Replace(repositoryURL, "://", "://"+credentials+"@", 1) + return cloneRepository(repositoryURL, destination) +} + +func cloneRepository(repositoryURL, destination string) error { + _, err := git.PlainClone(destination, false, &git.CloneOptions{ + URL: repositoryURL, + }) return err } diff --git a/api/http/handler/stack.go b/api/http/handler/stack.go index ff872896d..5b9e53187 100644 --- a/api/http/handler/stack.go +++ b/api/http/handler/stack.go @@ -70,12 +70,15 @@ func NewStackHandler(bouncer *security.RequestBouncer) *StackHandler { type ( postStacksRequest struct { - Name string `valid:"required"` - SwarmID string `valid:"required"` - StackFileContent string `valid:""` - GitRepository string `valid:""` - PathInRepository string `valid:""` - Env []portainer.Pair `valid:""` + Name string `valid:"required"` + SwarmID string `valid:"required"` + StackFileContent string `valid:""` + RepositoryURL string `valid:""` + RepositoryAuthentication bool `valid:""` + RepositoryUsername string `valid:""` + RepositoryPassword string `valid:""` + ComposeFilePathInRepository string `valid:""` + Env []portainer.Pair `valid:""` } postStacksResponse struct { ID string `json:"Id"` @@ -263,24 +266,20 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri } stackName := req.Name - if stackName == "" { - httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger) - return - } - swarmID := req.SwarmID - if swarmID == "" { + + if stackName == "" || swarmID == "" || req.RepositoryURL == "" { httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger) return } - if req.GitRepository == "" { + if req.RepositoryAuthentication && (req.RepositoryUsername == "" || req.RepositoryPassword == "") { httperror.WriteErrorResponse(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger) return } - if req.PathInRepository == "" { - req.PathInRepository = filesystem.ComposeFileDefaultName + if req.ComposeFilePathInRepository == "" { + req.ComposeFilePathInRepository = filesystem.ComposeFileDefaultName } stacks, err := handler.StackService.Stacks() @@ -300,7 +299,7 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri ID: portainer.StackID(stackName + "_" + swarmID), Name: stackName, SwarmID: swarmID, - EntryPoint: req.PathInRepository, + EntryPoint: req.ComposeFilePathInRepository, Env: req.Env, } @@ -314,7 +313,11 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri return } - err = handler.GitService.CloneRepository(req.GitRepository, projectPath) + if req.RepositoryAuthentication { + err = handler.GitService.ClonePrivateRepositoryWithBasicAuth(req.RepositoryURL, projectPath, req.RepositoryUsername, req.RepositoryPassword) + } else { + err = handler.GitService.ClonePublicRepository(req.RepositoryURL, projectPath) + } if err != nil { httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger) return diff --git a/api/portainer.go b/api/portainer.go index 8c60b9973..fc98a6b36 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -375,7 +375,8 @@ type ( // GitService represents a service for managing Git. GitService interface { - CloneRepository(url, destination string) error + ClonePublicRepository(repositoryURL, destination string) error + ClonePrivateRepositoryWithBasicAuth(repositoryURL, destination, username, password string) error } // EndpointWatcher represents a service to synchronize the endpoints via an external source. diff --git a/api/swagger.yaml b/api/swagger.yaml index 4d2546919..d326d53a6 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -2904,14 +2904,26 @@ definitions: type: "string" example: "version: 3\n services:\n web:\n image:nginx" description: "Content of the Stack file. Required when using the 'string' deployment method." - GitRepository: + RepositoryURL: type: "string" example: "https://github.com/openfaas/faas" - description: "URL of a public Git repository hosting the Stack file. Required when using the 'repository' deployment method." - PathInRepository: + description: "URL of a Git repository hosting the Stack file. Required when using the 'repository' deployment method." + ComposeFilePathInRepository: type: "string" example: "docker-compose.yml" description: "Path to the Stack file inside the Git repository. Required when using the 'repository' deployment method." + RepositoryAuthentication: + type: "boolean" + example: true + description: "Use basic authentication to clone the Git repository." + RepositoryUsername: + type: "string" + example: "myGitUsername" + description: "Username used in basic authentication. Required when RepositoryAuthentication is true." + RepositoryPassword: + type: "string" + example: "myGitPassword" + description: "Password used in basic authentication. Required when RepositoryAuthentication is true." Env: type: "array" description: "A list of environment variables used during stack deployment" diff --git a/app/docker/services/stackService.js b/app/docker/services/stackService.js index 1d3e65411..9d0a08e13 100644 --- a/app/docker/services/stackService.js +++ b/app/docker/services/stackService.js @@ -124,7 +124,7 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic return deferred.promise; }; - service.createStackFromGitRepository = function(name, gitRepository, pathInRepository, env) { + service.createStackFromGitRepository = function(name, repositoryOptions, env) { var deferred = $q.defer(); SwarmService.swarm() @@ -133,8 +133,11 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic var payload = { Name: name, SwarmID: swarm.Id, - GitRepository: gitRepository, - PathInRepository: pathInRepository, + RepositoryURL: repositoryOptions.RepositoryURL, + ComposeFilePathInRepository: repositoryOptions.ComposeFilePathInRepository, + RepositoryAuthentication: repositoryOptions.RepositoryAuthentication, + RepositoryUsername: repositoryOptions.RepositoryUsername, + RepositoryPassword: repositoryOptions.RepositoryPassword, Env: env }; return Stack.create({ method: 'repository' }, payload).$promise; diff --git a/app/docker/views/stacks/create/createStackController.js b/app/docker/views/stacks/create/createStackController.js index cc11a680b..18c32be8f 100644 --- a/app/docker/views/stacks/create/createStackController.js +++ b/app/docker/views/stacks/create/createStackController.js @@ -7,8 +7,11 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid StackFileContent: '', StackFile: null, RepositoryURL: '', + RepositoryAuthentication: false, + RepositoryUsername: '', + RepositoryPassword: '', Env: [], - RepositoryPath: 'docker-compose.yml', + ComposeFilePathInRepository: 'docker-compose.yml', AccessControlData: new AccessControlFormData() }; @@ -48,9 +51,14 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid var stackFile = $scope.formValues.StackFile; return StackService.createStackFromFileUpload(name, stackFile, env); } else if (method === 'repository') { - var gitRepository = $scope.formValues.RepositoryURL; - var pathInRepository = $scope.formValues.RepositoryPath; - return StackService.createStackFromGitRepository(name, gitRepository, pathInRepository, env); + var repositoryOptions = { + RepositoryURL: $scope.formValues.RepositoryURL, + ComposeFilePathInRepository: $scope.formValues.ComposeFilePathInRepository, + RepositoryAuthentication: $scope.formValues.RepositoryAuthentication, + RepositoryUsername: $scope.formValues.RepositoryUsername, + RepositoryPassword: $scope.formValues.RepositoryPassword + }; + return StackService.createStackFromGitRepository(name, repositoryOptions, env); } } @@ -76,19 +84,17 @@ function ($scope, $state, StackService, Authentication, Notifications, FormValid createStack(name, method) .then(function success(data) { Notifications.success('Stack successfully deployed'); + return ResourceControlService.applyResourceControl('stack', name, userId, accessControlData, []) + .then(function success() { + $state.go('docker.stacks'); + }) + .catch(function error(err) { + Notifications.error('Failure', err, 'Unable to apply resource control on the stack'); + }); }) .catch(function error(err) { Notifications.warning('Deployment error', err.err.data.err); }) - .then(function success(data) { - return ResourceControlService.applyResourceControl('stack', name, userId, accessControlData, []); - }) - .then(function success() { - $state.go('docker.stacks'); - }) - .catch(function error(err) { - Notifications.error('Failure', err, 'Unable to apply resource control on the stack'); - }) .finally(function final() { $scope.state.actionInProgress = false; }); diff --git a/app/docker/views/stacks/create/createstack.html b/app/docker/views/stacks/create/createstack.html index 943277edc..887dd2228 100644 --- a/app/docker/views/stacks/create/createstack.html +++ b/app/docker/views/stacks/create/createstack.html @@ -113,7 +113,7 @@
- You can use the URL of a public git repository. + You can use the URL of a git repository.
@@ -130,7 +130,29 @@
- + +
+
+
+
+ + +
+
+
+ +
+ +
+ +
+
@@ -174,7 +196,7 @@
+
+
+ + +
+