From ceaee4e1757e8ba6b32356a272566bf740844cb3 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Wed, 21 Sep 2022 10:10:58 +0300 Subject: [PATCH] refactor(ui): replace ng selectors with react-select [EE-3608] (#7203) Co-authored-by: LP B --- app/assets/css/app.css | 54 ------- app/assets/css/index.js | 2 - app/assets/css/theme.css | 38 ----- app/assets/css/vendor-override.css | 31 ---- app/docker/filters/filters.js | 11 +- app/docker/filters/utils.ts | 11 ++ .../edgeGroupsSelector.html | 20 --- .../components/edge-groups-selector/index.js | 10 -- .../editEdgeStackForm.html | 2 +- .../editEdgeStackFormController.js | 9 +- app/edge/react/components/index.ts | 13 +- .../create-edge-stack-view.controller.js | 10 +- .../create-edge-stack-view.html | 2 +- app/index.js | 2 - .../helm-templates-list.controller.js | 28 ++-- .../helm-templates-list.html | 23 ++- app/kubernetes/react/components/index.ts | 55 ++++++- .../kube-registry-access-view.controller.js | 12 +- .../kube-registry-access-view.html | 19 +-- app/kubernetes/views/configure/configure.html | 19 +-- .../views/configure/configureController.js | 23 ++- .../access/resourcePoolAccess.html | 22 +-- .../access/resourcePoolAccessController.js | 12 +- .../create/createResourcePool.html | 21 +-- .../create/createResourcePoolController.js | 7 + .../resource-pools/edit/resourcePool.html | 22 +-- .../edit/resourcePoolController.js | 7 + .../porAccessControlForm.html | 67 ++++---- .../porAccessControlFormController.js | 31 ++-- .../components/accessManagement/index.js | 6 +- .../index.js | 7 - .../por-access-management-users-selector.html | 20 --- .../accessManagement/porAccessManagement.html | 8 +- .../porAccessManagementController.js | 11 +- .../endpoint-selector/endpoint-selector.js | 9 -- .../endpoint-selector/endpointSelector.html | 8 - .../endpointSelectorController.js | 35 ---- .../stack-duplication-form-controller.js | 57 ++++++- .../stack-duplication-form.html | 4 +- .../environment.service/registries.ts | 1 + .../access-viewer/access-viewer.controller.js | 69 ++++---- .../access-viewer/access-viewer.html | 11 +- app/portainer/react/components/index.ts | 55 +++++++ .../ldap-custom-admin-group.controller.js | 21 +-- .../ldap-custom-admin-group.html | 28 ++-- app/portainer/views/users/users.html | 23 ++- app/portainer/views/users/usersController.js | 14 +- .../TeamsSelector/TeamsSelector.stories.tsx | 4 +- .../TeamsSelector/TeamsSelector.tsx | 21 ++- .../datatables/SortbySelector.module.css | 10 +- .../form-components/PortainerSelect.tsx | 149 ++++++++++++++++++ .../form-components/ReactSelect.css | 100 ++++++++++++ .../form-components/ReactSelect.module.css | 65 -------- .../form-components/ReactSelect.tsx | 61 +++++-- .../TemplateListSort.module.css | 8 +- .../edge/components/EdgeGroupsSelector.tsx | 34 ++++ .../StorageAccessModeSelector.tsx | 60 +++++++ .../RegistryAccessView/NamespacesSelector.tsx | 50 ++++++ .../NamespaceAccessUsersSelector.tsx | 82 ++++++++++ .../CreateNamespaceRegistriesSelector.tsx | 32 ++++ .../PorAccessManagementUsersSelector.tsx | 84 ++++++++++ .../PorAccessControlForm/TeamsSelector.tsx | 33 ++++ .../PorAccessControlForm/UsersSelector.tsx | 33 ++++ app/vendors.js | 2 - package.json | 2 - yarn.lock | 9 -- 66 files changed, 1186 insertions(+), 623 deletions(-) create mode 100644 app/docker/filters/utils.ts delete mode 100644 app/edge/components/edge-groups-selector/edgeGroupsSelector.html delete mode 100644 app/edge/components/edge-groups-selector/index.js delete mode 100644 app/portainer/components/accessManagement/por-access-management-users-selector/index.js delete mode 100644 app/portainer/components/accessManagement/por-access-management-users-selector/por-access-management-users-selector.html delete mode 100644 app/portainer/components/endpoint-selector/endpoint-selector.js delete mode 100644 app/portainer/components/endpoint-selector/endpointSelector.html delete mode 100644 app/portainer/components/endpoint-selector/endpointSelectorController.js create mode 100644 app/react/components/form-components/PortainerSelect.tsx create mode 100644 app/react/components/form-components/ReactSelect.css delete mode 100644 app/react/components/form-components/ReactSelect.module.css create mode 100644 app/react/edge/components/EdgeGroupsSelector.tsx create mode 100644 app/react/kubernetes/cluster/ConfigureView/StorageAccessModeSelector.tsx create mode 100644 app/react/kubernetes/cluster/RegistryAccessView/NamespacesSelector.tsx create mode 100644 app/react/kubernetes/namespaces/AccessView/NamespaceAccessUsersSelector.tsx create mode 100644 app/react/kubernetes/namespaces/CreateView/CreateNamespaceRegistriesSelector.tsx create mode 100644 app/react/portainer/access-control/AccessManagement/PorAccessManagementUsersSelector.tsx create mode 100644 app/react/portainer/access-control/PorAccessControlForm/TeamsSelector.tsx create mode 100644 app/react/portainer/access-control/PorAccessControlForm/UsersSelector.tsx diff --git a/app/assets/css/app.css b/app/assets/css/app.css index 96006395d..33f17f39b 100644 --- a/app/assets/css/app.css +++ b/app/assets/css/app.css @@ -692,60 +692,6 @@ input[type='checkbox'] { /*!bootbox override*/ -/*angular-multi-select override*/ -.multiSelect > button { - min-height: 30px !important; - background-image: var(--bg-image-multiselect-button); - border-color: var(--border-multiselect); - color: var(--text-multiselect); - background-color: var(--bg-multiselect-color); -} - -.multiSelect > button:hover { - background-image: var(--bg-image-multiselect-hover); -} - -.multiSelect .checkboxLayer { - border-color: var(--border-multiselect-checkboxlayer); -} - -.multiSelect .checkBoxContainer { - background-color: var(--bg-multiselect-checkboxcontainer); -} - -.multiSelect .multiSelectItem { - color: var(--text-multiselect-item); -} - -.multiSelect .helperContainer { - background-color: var(--bg-multiselect-helpercontainer); -} - -.multiSelect .multiSelectFocus { - background-image: var(--bg-image-multiselect); -} - -.multiSelect .multiSelectItem:not(.multiSelectGroup).selected { - background-image: var(--bg-image-multiselect); - color: var(--white-color); - border: none; -} - -.multiSelect .multiSelectItem:hover, -.multiSelect .multiSelectGroup:hover { - border-color: var(--grey-3); - background-image: var(--bg-image-multiselect) !important; - color: var(--white-color) !important; -} - -.multiSelect .tickMark, -.widget .widget-body table tbody .multiSelect .tickMark { - top: 2px; - right: 12px; - font-size: 20px !important; -} -/*!angular-multi-select override*/ - /*toaster override*/ #toast-container > div { opacity: 0.9; diff --git a/app/assets/css/index.js b/app/assets/css/index.js index 38010d225..5bdaebbed 100644 --- a/app/assets/css/index.js +++ b/app/assets/css/index.js @@ -1,4 +1,3 @@ -import 'ui-select/dist/select.css'; import 'bootstrap/dist/css/bootstrap.css'; import '@fortawesome/fontawesome-free/css/brands.css'; import '@fortawesome/fontawesome-free/css/solid.css'; @@ -11,7 +10,6 @@ import 'codemirror/addon/lint/lint.css'; import 'angular-json-tree/dist/angular-json-tree.css'; import 'angular-loading-bar/build/loading-bar.css'; import 'angular-moment-picker/dist/angular-moment-picker.min.css'; -import 'angular-multiselect/isteven-multi-select.css'; import 'spinkit/spinkit.min.css'; import '@reach/menu-button/styles.css'; diff --git a/app/assets/css/theme.css b/app/assets/css/theme.css index c1505e5bf..e0827377d 100644 --- a/app/assets/css/theme.css +++ b/app/assets/css/theme.css @@ -125,7 +125,6 @@ --border-pagination-color: var(--ui-white); --bg-pagination-span-color: var(--white-color); --bg-pagination-hover-color: var(--ui-blue-3); - --bg-ui-select-hover-color: var(--grey-14); --bg-motd-body-color: var(--grey-20); --bg-item-highlighted-color: var(--grey-21); --bg-item-highlighted-null-color: var(--grey-14); @@ -135,7 +134,6 @@ --bg-input-sm-color: var(--white-color); --bg-app-datatable-thead: var(--grey-23); --bg-app-datatable-tbody: var(--grey-24); - --bg-multiselect-color: var(--white-color); --bg-daterangepicker-color: var(--white-color); --bg-calendar-color: var(--white-color); --bg-calendar-table-color: var(--white-color); @@ -194,8 +192,6 @@ --text-pagination-color: var(--grey-26); --text-pagination-span-color: var(--grey-3); --text-pagination-span-hover-color: var(--grey-3); - --text-ui-select-color: var(--grey-6); - --text-ui-select-hover-color: var(--grey-28); --text-summary-color: var(--black-color); --text-tooltip-color: var(--white-color); --text-rzslider-color: var(--grey-36); @@ -253,16 +249,6 @@ --button-opacity: 0.2; --button-opacity-hover: 0.5; - --bg-image-multiselect: linear-gradient(var(--blue-2), var(--blue-2)); - --bg-image-multiselect-button: linear-gradient(var(--white-color), var(--grey-17)); - --bg-image-multiselect-hover: linear-gradient(var(--white-color), var(--grey-43)); - --border-multiselect: var(--grey-48); - --border-multiselect-checkboxlayer: var(--grey-51); - --text-multiselect: var(--grey-29); - --text-multiselect-selectitem: var(--white-color); - --bg-multiselect-checkboxcontainer: var(--white-color); - --text-multiselect-item: var(--grey-30); - --bg-multiselect-helpercontainer: var(--white-color); --text-input-textarea: var(--white-color); --user-menu-icon-color: var(--ui-gray-4); @@ -315,7 +301,6 @@ --bg-pagination-color: var(--grey-3); --bg-pagination-span-color: var(--grey-1); --bg-pagination-hover-color: var(--grey-3); - --bg-ui-select-hover-color: var(--grey-3); --bg-motd-body-color: var(--grey-1); --bg-item-highlighted-color: var(--grey-2); --bg-item-highlighted-null-color: var(--grey-2); @@ -328,7 +313,6 @@ --bg-app-datatable-thead: var(--grey-1); --bg-service-datatable-tbody: var(--grey-1); --bg-app-datatable-tbody: var(--grey-1); - --bg-multiselect-color: var(--grey-1); --bg-daterangepicker-color: var(--grey-3); --bg-calendar-color: var(--grey-3); --bg-calendar-table-color: var(--grey-3); @@ -386,8 +370,6 @@ --text-pagination-color: var(--white-color); --text-pagination-span-color: var(--ui-white); --text-pagination-span-hover-color: var(--ui-white); - --text-ui-select-color: var(--white-color); - --text-ui-select-hover-color: var(--white-color); --text-summary-color: var(--white-color); --text-boxselector-wrapper-color: var(--white-color); --text-tooltip-color: var(--white-color); @@ -447,15 +429,6 @@ --shadow-box-color: none; --shadow-boxselector-color: none; - --bg-image-multiselect: linear-gradient(var(--grey-38), var(--grey-38)); - --bg-image-multiselect-button: linear-gradient(var(--grey-1), var(--grey-1)); - --bg-image-multiselect-hover: linear-gradient(var(--grey-3), var(--grey-3)); - --border-multiselect: var(--grey-3); - --border-multiselect-checkboxlayer: var(--grey-3); - --text-multiselect: var(--white-color); - --bg-multiselect-checkboxcontainer: var(--grey-3); - --text-multiselect-item: var(--white-color); - --bg-multiselect-helpercontainer: var(--grey-1); --text-input-textarea: var(--grey-1); --user-menu-icon-color: var(--grey-3); @@ -508,7 +481,6 @@ --bg-app-datatable-tbody: var(--black-color); --bg-pagination-color: var(--grey-3); --bg-pagination-span-color: var(--ui-black); - --bg-multiselect-color: var(--grey-1); --bg-daterangepicker-color: var(--black-color); --bg-calendar-color: var(--black-color); --bg-calendar-table-color: var(--black-color); @@ -568,7 +540,6 @@ --text-daterangepicker-end-date: var(--ui-white); --text-daterangepicker-in-range: var(--white-color); --text-daterangepicker-active: var(--white-color); - --text-ui-select-color: var(--white-color); --text-json-tree-color: var(--white-color); --text-json-tree-leaf-color: var(--white-color); --text-json-tree-branch-preview-color: var(--white-color); @@ -619,15 +590,6 @@ --shadow-box-color: none; --shadow-boxselector-color: none; - --bg-image-multiselect: linear-gradient(var(--black-color), var(--black-color)); - --bg-image-multiselect-button: linear-gradient(var(--grey-1), var(--grey-1)); - --bg-image-multiselect-hover: linear-gradient(var(--grey-3), var(--grey-3)); - --border-multiselect: var(--black-color); - --border-multiselect-checkboxlayer: var(--grey-3); - --text-multiselect: var(--white-color); - --bg-multiselect-checkboxcontainer: var(--grey-3); - --text-multiselect-item: var(--white-color); - --bg-multiselect-helpercontainer: var(--grey-1); --text-input-textarea: var(--black-color); --bg-item-highlighted-null-color: var(--grey-2); --text-cm-default-color: var(--blue-9); diff --git a/app/assets/css/vendor-override.css b/app/assets/css/vendor-override.css index d29639a7d..5c0fc7570 100644 --- a/app/assets/css/vendor-override.css +++ b/app/assets/css/vendor-override.css @@ -245,37 +245,6 @@ json-tree .branch-preview { background-color: var(--bg-progress-color); } -.ui-select-search, -.ui-select-toggle { - height: 30px; - min-width: 260px; - padding: 4px 12px; -} - -.ui-select-toggle { - justify-content: flex-start !important; -} - -.ui-select-match-text { - display: flex; - flex-direction: row-reverse; - align-items: center; -} - -.ui-select-match-text > a { - verical-align: middle; -} - -.ui-select-bootstrap .ui-select-choices-row > span { - color: var(--text-ui-select-color); -} - -.ui-select-bootstrap .ui-select-choices-row > span:hover, -.ui-select-bootstrap .ui-select-choices-row > span:focus { - background-color: var(--bg-ui-select-hover-color); - color: var(--text-ui-select-hover-color); -} - .motd-body { background-color: var(--bg-motd-body-color) !important; } diff --git a/app/docker/filters/filters.js b/app/docker/filters/filters.js index c41006159..a72418944 100644 --- a/app/docker/filters/filters.js +++ b/app/docker/filters/filters.js @@ -1,4 +1,5 @@ import _ from 'lodash-es'; +import { trimSHA } from './utils'; function includeString(text, values) { return values.some(function (val) { @@ -253,15 +254,7 @@ angular }) .filter('trimshasum', function () { 'use strict'; - return function (imageName) { - if (!imageName) { - return; - } - if (imageName.indexOf('sha256:') === 0) { - return imageName.substring(7, 19); - } - return _.split(imageName, '@sha256')[0]; - }; + return trimSHA; }) .filter('trimversiontag', function () { 'use strict'; diff --git a/app/docker/filters/utils.ts b/app/docker/filters/utils.ts new file mode 100644 index 000000000..ea26e6960 --- /dev/null +++ b/app/docker/filters/utils.ts @@ -0,0 +1,11 @@ +import _ from 'lodash'; + +export function trimSHA(imageName: string) { + if (!imageName) { + return ''; + } + if (imageName.indexOf('sha256:') === 0) { + return imageName.substring(7, 19); + } + return _.split(imageName, '@sha256')[0]; +} diff --git a/app/edge/components/edge-groups-selector/edgeGroupsSelector.html b/app/edge/components/edge-groups-selector/edgeGroupsSelector.html deleted file mode 100644 index 1210f3cb0..000000000 --- a/app/edge/components/edge-groups-selector/edgeGroupsSelector.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - {{ $item.Name }} - - - - - {{ item.Name }} - - - diff --git a/app/edge/components/edge-groups-selector/index.js b/app/edge/components/edge-groups-selector/index.js deleted file mode 100644 index 902139191..000000000 --- a/app/edge/components/edge-groups-selector/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import angular from 'angular'; - -angular.module('portainer.edge').component('edgeGroupsSelector', { - templateUrl: './edgeGroupsSelector.html', - bindings: { - model: '<', - items: '<', - onChange: '<', - }, -}); diff --git a/app/edge/components/edit-edge-stack-form/editEdgeStackForm.html b/app/edge/components/edit-edge-stack-form/editEdgeStackForm.html index cc1a70713..0bcdeaa05 100644 --- a/app/edge/components/edit-edge-stack-form/editEdgeStackForm.html +++ b/app/edge/components/edit-edge-stack-form/editEdgeStackForm.html @@ -2,7 +2,7 @@
Edge Groups
- +
diff --git a/app/edge/components/edit-edge-stack-form/editEdgeStackFormController.js b/app/edge/components/edit-edge-stack-form/editEdgeStackFormController.js index b84bda5a6..00586c689 100644 --- a/app/edge/components/edit-edge-stack-form/editEdgeStackFormController.js +++ b/app/edge/components/edit-edge-stack-form/editEdgeStackFormController.js @@ -2,7 +2,8 @@ import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models'; export class EditEdgeStackFormController { /* @ngInject */ - constructor() { + constructor($scope) { + this.$scope = $scope; this.state = { endpointTypes: [], }; @@ -32,9 +33,11 @@ export class EditEdgeStackFormController { } onChangeGroups(groups) { - this.model.EdgeGroups = groups; + return this.$scope.$evalAsync(() => { + this.model.EdgeGroups = groups; - this.checkEndpointTypes(groups); + this.checkEndpointTypes(groups); + }); } isFormValid() { diff --git a/app/edge/react/components/index.ts b/app/edge/react/components/index.ts index 3532c5a31..27c210103 100644 --- a/app/edge/react/components/index.ts +++ b/app/edge/react/components/index.ts @@ -1,6 +1,11 @@ import angular from 'angular'; -export const componentsModule = angular.module( - 'portainer.edge.react.components', - [] -).name; +import { EdgeGroupsSelector } from '@/react/edge/components/EdgeGroupsSelector'; +import { r2a } from '@/react-tools/react2angular'; + +export const componentsModule = angular + .module('portainer.edge.react.components', []) + .component( + 'edgeGroupsSelector', + r2a(EdgeGroupsSelector, ['items', 'onChange', 'value']) + ).name; diff --git a/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.controller.js b/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.controller.js index e404f9f4f..a9b2a469a 100644 --- a/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.controller.js +++ b/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.controller.js @@ -1,7 +1,7 @@ export default class CreateEdgeStackViewController { /* @ngInject */ - constructor($state, $window, ModalService, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async) { - Object.assign(this, { $state, $window, ModalService, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async }); + constructor($state, $window, ModalService, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async, $scope) { + Object.assign(this, { $state, $window, ModalService, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async, $scope }); this.formValues = { Name: '', @@ -119,9 +119,11 @@ export default class CreateEdgeStackViewController { } onChangeGroups(groups) { - this.formValues.Groups = groups; + return this.$scope.$evalAsync(() => { + this.formValues.Groups = groups; - this.checkIfEndpointTypes(groups); + this.checkIfEndpointTypes(groups); + }); } checkIfEndpointTypes(groups) { diff --git a/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.html b/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.html index a8618348e..feceb774f 100644 --- a/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.html +++ b/app/edge/views/edge-stacks/createEdgeStackView/create-edge-stack-view.html @@ -34,7 +34,7 @@
Edge Groups
- +
No Edge groups are available. Head over to the Edge groups view to create one. diff --git a/app/index.js b/app/index.js index 5c7aa6a61..7ffa7c2e2 100644 --- a/app/index.js +++ b/app/index.js @@ -28,8 +28,6 @@ angular 'ui.bootstrap', 'ui.router', UI_ROUTER_REACT_HYBRID, - 'ui.select', - 'isteven-multi-select', 'ngSanitize', 'ngFileUpload', 'ngMessages', diff --git a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.controller.js b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.controller.js index 3cc36456b..7ab749cbc 100644 --- a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.controller.js +++ b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.controller.js @@ -1,12 +1,20 @@ export default class HelmTemplatesListController { /* @ngInject */ - constructor($async, DatatableService, HelmService, Notifications) { + constructor($async, $scope, DatatableService, HelmService, Notifications) { this.$async = $async; + this.$scope = $scope; this.DatatableService = DatatableService; this.HelmService = HelmService; this.Notifications = Notifications; + this.state = { + textFilter: '', + selectedCategory: '', + categories: [], + }; + this.updateCategories = this.updateCategories.bind(this); + this.onCategoryChange = this.onCategoryChange.bind(this); } async updateCategories() { @@ -16,18 +24,20 @@ export default class HelmTemplatesListController { .filter((a) => a) // filter out undefined/nulls .map((c) => c.category); // get annotation category const availableCategories = [...new Set(annotationCategories)].sort(); // unique and sort - this.state.categories = availableCategories; + this.state.categories = availableCategories.map((cat) => ({ label: cat, value: cat })); } catch (err) { this.Notifications.error('Failure', err, 'Unable to retrieve helm charts categories'); } } - onTextFilterChange() { - this.DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); + onCategoryChange(value) { + return this.$scope.$evalAsync(() => { + this.state.selectedCategory = value || ''; + }); } - clearCategory() { - this.state.selectedCategory = ''; + onTextFilterChange() { + this.DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter); } $onChanges() { @@ -38,12 +48,6 @@ export default class HelmTemplatesListController { $onInit() { return this.$async(async () => { - this.state = { - textFilter: '', - selectedCategory: '', - categories: [], - }; - const textFilter = this.DatatableService.getDataTableTextFilters(this.tableKey); if (textFilter !== null) { this.state.textFilter = textFilter; diff --git a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html index 008be1421..a7a6b965b 100644 --- a/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html +++ b/app/kubernetes/components/helm/helm-templates/helm-templates-list/helm-templates-list.html @@ -22,24 +22,21 @@ ng-model-options="{ debounce: 300 }" />
-
- - - - - - {{ $select.selected }} - - - {{ category }} - - +
+
value), ...this.selectedResourcePools.map((pool) => pool.name)]); + return this.updateNamespaces([...this.savedResourcePools.map(({ value }) => value), ...this.selectedResourcePools]); } handleRemove(namespaces) { @@ -52,6 +54,12 @@ export default class KubernetesRegistryAccessController { }); } + onChangeResourcePools(resourcePools) { + return this.$scope.$evalAsync(() => { + this.selectedResourcePools = resourcePools; + }); + } + $onInit() { return this.$async(async () => { try { diff --git a/app/kubernetes/registries/kube-registry-access-view/kube-registry-access-view.html b/app/kubernetes/registries/kube-registry-access-view/kube-registry-access-view.html index 56eaf8797..96831478a 100644 --- a/app/kubernetes/registries/kube-registry-access-view/kube-registry-access-view.html +++ b/app/kubernetes/registries/kube-registry-access-view/kube-registry-access-view.html @@ -12,19 +12,14 @@
No namespaces available. - - + value="$ctrl.selectedResourcePools" + namespaces="$ctrl.resourcePools" + placeholder="'Select one or more namespaces'" + on-change="($ctrl.onChangeResourcePools)" + >
diff --git a/app/kubernetes/views/configure/configure.html b/app/kubernetes/views/configure/configure.html index b45c1ab46..7d3abf977 100644 --- a/app/kubernetes/views/configure/configure.html +++ b/app/kubernetes/views/configure/configure.html @@ -299,19 +299,12 @@
- - +
diff --git a/app/kubernetes/views/configure/configureController.js b/app/kubernetes/views/configure/configureController.js index 6f644a6bf..3058ecb4b 100644 --- a/app/kubernetes/views/configure/configureController.js +++ b/app/kubernetes/views/configure/configureController.js @@ -45,6 +45,7 @@ class KubernetesConfigureController { this.limitedFeatureAutoWindow = FeatureId.HIDE_AUTO_UPDATE_WINDOW; this.onToggleAutoUpdate = this.onToggleAutoUpdate.bind(this); this.onChangeEnableResourceOverCommit = this.onChangeEnableResourceOverCommit.bind(this); + this.onChangeStorageClassAccessMode = this.onChangeStorageClassAccessMode.bind(this); } /* #endregion */ @@ -263,6 +264,18 @@ class KubernetesConfigureController { }); } + onChangeStorageClassAccessMode(storageClassName, accessModes) { + return this.$scope.$evalAsync(() => { + const storageClass = this.StorageClasses.find((item) => item.Name === storageClassName); + + if (!storageClass) { + throw new Error('Storage class not found'); + } + + storageClass.AccessModes = accessModes; + }); + } + /* #region ON INIT */ async onInit() { this.state = { @@ -288,18 +301,14 @@ class KubernetesConfigureController { }; try { + this.availableAccessModes = new KubernetesStorageClassAccessPolicies(); + [this.StorageClasses, this.endpoint] = await Promise.all([this.KubernetesStorageService.get(this.state.endpointId), this.EndpointService.endpoint(this.state.endpointId)]); _.forEach(this.StorageClasses, (item) => { - item.availableAccessModes = new KubernetesStorageClassAccessPolicies(); const storage = _.find(this.endpoint.Kubernetes.Configuration.StorageClasses, (sc) => sc.Name === item.Name); if (storage) { item.selected = true; - _.forEach(storage.AccessModes, (access) => { - const mode = _.find(item.availableAccessModes, { Name: access }); - if (mode) { - mode.selected = true; - } - }); + item.AccessModes = storage.AccessModes.map((name) => this.availableAccessModes.find((accessMode) => accessMode.Name === name)); } }); diff --git a/app/kubernetes/views/resource-pools/access/resourcePoolAccess.html b/app/kubernetes/views/resource-pools/access/resourcePoolAccess.html index e0e008e54..295d881f7 100644 --- a/app/kubernetes/views/resource-pools/access/resourcePoolAccess.html +++ b/app/kubernetes/views/resource-pools/access/resourcePoolAccess.html @@ -52,25 +52,19 @@
- +
No user nor team access has been set on the environment. Head over to the Environments view to manage them. - - + input-id="users-selector" + value="ctrl.formValues.multiselectOutput" + options="ctrl.availableUsersAndTeams" + on-change="(ctrl.onUsersAndTeamsChange)" + >
@@ -80,7 +74,7 @@
- +
No registries available. Head over to the registry view to define a container registry. @@ -411,20 +411,13 @@ No registries available. Contact your administrator to create a container registry. - - +
diff --git a/app/kubernetes/views/resource-pools/create/createResourcePoolController.js b/app/kubernetes/views/resource-pools/create/createResourcePoolController.js index 8c8987ad3..02d125f5a 100644 --- a/app/kubernetes/views/resource-pools/create/createResourcePoolController.js +++ b/app/kubernetes/views/resource-pools/create/createResourcePoolController.js @@ -39,6 +39,7 @@ class KubernetesCreateResourcePoolController { this.onToggleStorageQuota = this.onToggleStorageQuota.bind(this); this.onToggleLoadBalancerQuota = this.onToggleLoadBalancerQuota.bind(this); this.onToggleResourceQuota = this.onToggleResourceQuota.bind(this); + this.onRegistriesChange = this.onRegistriesChange.bind(this); } /* #endregion */ @@ -92,6 +93,12 @@ class KubernetesCreateResourcePoolController { }); } + onRegistriesChange(registries) { + return this.$scope.$evalAsync(() => { + this.formValues.Registries = registries; + }); + } + addHostname(ingressClass) { ingressClass.Hosts.push(new KubernetesResourcePoolIngressClassHostFormValue()); } diff --git a/app/kubernetes/views/resource-pools/edit/resourcePool.html b/app/kubernetes/views/resource-pools/edit/resourcePool.html index cd612187c..f7b3704e5 100644 --- a/app/kubernetes/views/resource-pools/edit/resourcePool.html +++ b/app/kubernetes/views/resource-pools/edit/resourcePool.html @@ -364,27 +364,21 @@
- -
+ +
No registries available. Head over to the registry view to define a container registry. No registries available. Contact your administrator to create a container registry. - - +
diff --git a/app/kubernetes/views/resource-pools/edit/resourcePoolController.js b/app/kubernetes/views/resource-pools/edit/resourcePoolController.js index 56eb3f020..1aa1480cf 100644 --- a/app/kubernetes/views/resource-pools/edit/resourcePoolController.js +++ b/app/kubernetes/views/resource-pools/edit/resourcePoolController.js @@ -73,6 +73,7 @@ class KubernetesResourcePoolController { this.getEvents = this.getEvents.bind(this); this.onToggleLoadBalancersQuota = this.onToggleLoadBalancersQuota.bind(this); this.onToggleStorageQuota = this.onToggleStorageQuota.bind(this); + this.onRegistriesChange = this.onRegistriesChange.bind(this); } /* #endregion */ @@ -101,6 +102,12 @@ class KubernetesResourcePoolController { } /* #endregion */ + onRegistriesChange(registries) { + return this.$scope.$evalAsync(() => { + this.formValues.Registries = registries; + }); + } + onToggleLoadBalancersQuota(checked) { return this.$scope.$evalAsync(() => { this.formValues.UseLoadBalancersQuota = checked; diff --git a/app/portainer/components/accessControlForm/porAccessControlForm.html b/app/portainer/components/accessControlForm/porAccessControlForm.html index 645c9cfaa..2558c0452 100644 --- a/app/portainer/components/accessControlForm/porAccessControlForm.html +++ b/app/portainer/components/accessControlForm/porAccessControlForm.html @@ -72,8 +72,8 @@ class="form-group mt-4" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))" > -
-