From 01dc9066b72dc6927e99228dfd4af2ea545ce571 Mon Sep 17 00:00:00 2001 From: Chaim Lev-Ari Date: Mon, 23 May 2022 17:32:51 +0300 Subject: [PATCH] refactor(wizard): migrate to react [EE-2305] (#6957) --- api/http/handler/endpoints/endpoint_create.go | 9 + api/http/handler/endpoints/endpoint_list.go | 21 ++ api/http/handler/endpoints/endpoint_update.go | 13 +- api/http/handler/endpoints/unique_name.go | 18 ++ app/angulartics.matomo/analytics-services.ts | 14 + .../EdgeDevicesDatatableContainer.tsx | 3 +- .../WaitingRoomView/WaitingRoomView.tsx | 2 +- app/portainer/__module.js | 22 -- .../FileUpload/FileUploadField.stories.tsx | 9 +- .../FileUpload/FileUploadField.test.tsx | 6 +- .../FileUpload/FileUploadField.tsx | 3 + .../FileUpload/FileUploadForm.tsx | 1 + .../FormControl/FormControl.module.css | 5 - .../FormControl/FormControl.tsx | 29 ++- .../FormSection/FormSection.stories.tsx | 43 ++++ .../FormSection/FormSection.tsx | 39 +++ .../form-components/FormSection/index.ts | 1 + .../form-components/ReactSelect.tsx | 16 ++ .../environment.service/create.ts | 243 +++++++++++------- .../environments/environment.service/index.ts | 1 + app/portainer/environments/queries.ts | 56 ---- .../environments/queries/useAgentDetails.ts | 17 ++ .../queries/useCreateEnvironmentMutation.ts | 61 +++++ .../queries/useEnvironmentList.ts | 70 +++++ app/portainer/environments/utils.ts | 4 + app/portainer/helpers/yup-file-validation.ts | 43 ++++ .../EnvironmentItem/EdgeIndicator.test.tsx | 1 + .../EnvironmentItem/EdgeIndicator.tsx | 4 +- .../EnvironmentList/EnvironmentItem/index.ts | 1 + .../home/EnvironmentList/EnvironmentList.tsx | 7 +- app/portainer/react/components/index.ts | 2 +- app/portainer/react/index.ts | 2 +- app/portainer/react/views/index.ts | 9 +- app/portainer/react/views/wizard.ts | 57 ++++ .../SettingsOpenAMT/SettingsOpenAMT.tsx | 1 + app/portainer/tags/queries.ts | 35 ++- app/portainer/views/wizard/index.js | 7 - .../views/wizard/wizard-endpoints/index.js | 8 - .../wizard-endpoint-aci/index.js | 11 - .../wizard-aci.controller.js | 65 ----- .../wizard-endpoint-aci/wizard-aci.html | 67 ----- .../wizard-endpoint-docker/index.js | 11 - .../wizard-docker.controller.js | 237 ----------------- .../wizard-endpoint-docker/wizard-docker.html | 177 ------------- .../wizard-endpoint-kubernetes/index.js | 11 - .../wizard-kubernetes.controller.js | 114 -------- .../wizard-kubernetes.html | 65 ----- .../wizard-endpoint-list/index.js | 9 - .../wizard-endpoint-list.html | 11 - .../wizard-endpoints.controller.js | 196 -------------- .../wizard-endpoints/wizard-endpoints.css | 155 ----------- .../wizard-endpoints/wizard-endpoints.html | 94 ------- .../wizard-endpoints/wizard-stepper/index.js | 9 - .../wizard-endpoint-type/index.js | 11 - .../wizard-endpoint-type.html | 12 - .../wizard-stepper/wizard-stepper.html | 6 - .../views/wizard/wizard-link/index.js | 11 - .../views/wizard/wizard-link/wizard-link.html | 7 - .../views/wizard/wizard-tls/index.js | 9 - .../views/wizard/wizard-tls/wizard-tls.html | 49 ---- .../views/wizard/wizard-view.controller.js | 87 ------- app/portainer/views/wizard/wizard-view.html | 48 ---- app/react-tools/react-query.ts | 6 +- .../components/Stepper/Stepper.module.css} | 46 ++-- .../components/Stepper/Stepper.stories.tsx | 43 ++++ app/react/components/Stepper/Stepper.tsx | 33 +++ app/react/components/Stepper/index.ts | 1 + .../TagSelector/TagSelector.module.css | 4 + .../TagSelector/TagSelector.stories.tsx | 25 ++ .../TagSelector/TagSelector.test.tsx | 61 +++++ .../components/TagSelector/TagSelector.tsx | 118 +++++++++ app/react/components/TagSelector/index.ts | 1 + app/react/portainer/environments/wizard/.keep | 0 .../EndpointTypeView.tsx | 67 +++++ .../EnvironmentSelector.tsx | 46 ++++ .../environment-types.ts | 21 ++ .../wizard/EnvironmentTypeSelectView/index.ts | 1 + .../EnvironmentsCreationView.module.css | 16 ++ .../EnvironmentsCreationView.tsx | 206 +++++++++++++++ .../WizardAzure/WizardAzure.tsx | 167 ++++++++++++ .../WizardAzure/index.ts | 1 + .../WizardDocker/APITab/APIForm.tsx | 131 ++++++++++ .../APITab/APIForm.validation.tsx | 18 ++ .../WizardDocker/APITab/APITab.tsx | 20 ++ .../WizardDocker/APITab/DeploymentScripts.tsx | 63 +++++ .../WizardDocker/APITab/TLSFieldset.tsx | 106 ++++++++ .../WizardDocker/APITab/index.ts | 1 + .../WizardDocker/APITab/types.ts | 12 + .../WizardDocker/AgentTab/AgentTab.tsx | 21 ++ .../AgentTab/DeploymentScripts.tsx | 78 ++++++ .../WizardDocker/AgentTab/index.ts | 1 + .../WizardDocker/SocketTab/SocketForm.tsx | 112 ++++++++ .../SocketTab/SocketForm.validation.tsx | 23 ++ .../WizardDocker/SocketTab/SocketTab.tsx | 21 ++ .../WizardDocker/SocketTab/index.ts | 1 + .../WizardDocker/SocketTab/types.ts | 8 + .../WizardDocker/WizardDocker.tsx | 68 +++++ .../WizardDocker/index.ts | 1 + .../WizardEndpointsList.module.css} | 0 .../WizardEndpointsList.tsx | 81 ++++++ .../WizardEndpointsList/index.ts | 1 + .../WizardKubernetes/AgentPanel.tsx | 22 ++ .../WizardKubernetes/DeploymentScripts.tsx | 114 ++++++++ .../WizardKubernetes/WizardKubernetes.tsx | 55 ++++ .../WizardKubernetes/index.ts | 1 + .../wizard/EnvironmentsCreationView/index.ts | 1 + .../shared/AgentForm/AgentForm.tsx | 75 ++++++ .../shared/AgentForm/AgentForm.validation.tsx | 14 + .../shared/AgentForm/EnvironmentUrlField.tsx | 25 ++ .../shared/AgentForm/index.tsx | 1 + .../shared/MetadataFieldset/GroupsField.tsx | 36 +++ .../MetadataFieldset/MetadataFieldset.tsx | 25 ++ .../shared/MetadataFieldset/index.ts | 1 + .../shared/MetadataFieldset/validation.ts | 10 + .../shared/NameField.tsx | 58 +++++ .../wizard/EnvironmentsCreationView/types.ts | 12 + .../wizard/HomeView/HomeView.module.css} | 24 +- .../environments/wizard/HomeView/HomeView.tsx | 105 ++++++++ .../environments/wizard/HomeView/index.ts | 1 + .../useFetchOrCreateLocalEnvironment.ts | 84 ++++++ .../components/Option/Option.module.css | 37 +++ .../wizard/components/Option/Option.tsx | 46 ++++ .../wizard/components/Option/index.ts | 1 + .../portainer/environments/wizard/index.ts | 3 + tailwind.config.js | 2 +- 125 files changed, 2994 insertions(+), 1744 deletions(-) create mode 100644 api/http/handler/endpoints/unique_name.go create mode 100644 app/portainer/components/form-components/FormSection/FormSection.stories.tsx create mode 100644 app/portainer/components/form-components/FormSection/FormSection.tsx create mode 100644 app/portainer/components/form-components/FormSection/index.ts delete mode 100644 app/portainer/environments/queries.ts create mode 100644 app/portainer/environments/queries/useAgentDetails.ts create mode 100644 app/portainer/environments/queries/useCreateEnvironmentMutation.ts create mode 100644 app/portainer/environments/queries/useEnvironmentList.ts create mode 100644 app/portainer/helpers/yup-file-validation.ts create mode 100644 app/portainer/react/views/wizard.ts delete mode 100644 app/portainer/views/wizard/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.controller.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-aci/wizard-aci.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.controller.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-docker/wizard-docker.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.controller.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-kubernetes/wizard-kubernetes.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-list/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoint-list/wizard-endpoint-list.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoints.controller.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoints.css delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-endpoints.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-stepper/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-stepper/wizard-endpoint-type/index.js delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-stepper/wizard-endpoint-type/wizard-endpoint-type.html delete mode 100644 app/portainer/views/wizard/wizard-endpoints/wizard-stepper/wizard-stepper.html delete mode 100644 app/portainer/views/wizard/wizard-link/index.js delete mode 100644 app/portainer/views/wizard/wizard-link/wizard-link.html delete mode 100644 app/portainer/views/wizard/wizard-tls/index.js delete mode 100644 app/portainer/views/wizard/wizard-tls/wizard-tls.html delete mode 100644 app/portainer/views/wizard/wizard-view.controller.js delete mode 100644 app/portainer/views/wizard/wizard-view.html rename app/{portainer/views/wizard/wizard-endpoints/wizard-stepper/wizard-stepper.css => react/components/Stepper/Stepper.module.css} (67%) create mode 100644 app/react/components/Stepper/Stepper.stories.tsx create mode 100644 app/react/components/Stepper/Stepper.tsx create mode 100644 app/react/components/Stepper/index.ts create mode 100644 app/react/components/TagSelector/TagSelector.module.css create mode 100644 app/react/components/TagSelector/TagSelector.stories.tsx create mode 100644 app/react/components/TagSelector/TagSelector.test.tsx create mode 100644 app/react/components/TagSelector/TagSelector.tsx create mode 100644 app/react/components/TagSelector/index.ts delete mode 100644 app/react/portainer/environments/wizard/.keep create mode 100644 app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EndpointTypeView.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentTypeSelectView/EnvironmentSelector.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentTypeSelectView/environment-types.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentTypeSelectView/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.module.css create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/EnvironmentsCreationView.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardAzure/WizardAzure.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardAzure/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/APIForm.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/APIForm.validation.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/APITab.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/DeploymentScripts.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/TLSFieldset.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/APITab/types.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/AgentTab/AgentTab.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/AgentTab/DeploymentScripts.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/AgentTab/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/SocketTab/SocketForm.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/SocketTab/SocketForm.validation.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/SocketTab/SocketTab.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/SocketTab/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/SocketTab/types.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/WizardDocker.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardDocker/index.ts rename app/{portainer/views/wizard/wizard-endpoints/wizard-endpoint-list/wizard-endpoint-list.css => react/portainer/environments/wizard/EnvironmentsCreationView/WizardEndpointsList/WizardEndpointsList.module.css} (100%) create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardEndpointsList/WizardEndpointsList.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardEndpointsList/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardKubernetes/AgentPanel.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardKubernetes/DeploymentScripts.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardKubernetes/WizardKubernetes.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/WizardKubernetes/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/AgentForm/AgentForm.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/AgentForm/AgentForm.validation.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/AgentForm/EnvironmentUrlField.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/AgentForm/index.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/MetadataFieldset/GroupsField.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/MetadataFieldset/MetadataFieldset.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/MetadataFieldset/index.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/MetadataFieldset/validation.ts create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/shared/NameField.tsx create mode 100644 app/react/portainer/environments/wizard/EnvironmentsCreationView/types.ts rename app/{portainer/views/wizard/wizard-link/wizard-link.css => react/portainer/environments/wizard/HomeView/HomeView.module.css} (58%) create mode 100644 app/react/portainer/environments/wizard/HomeView/HomeView.tsx create mode 100644 app/react/portainer/environments/wizard/HomeView/index.ts create mode 100644 app/react/portainer/environments/wizard/HomeView/useFetchOrCreateLocalEnvironment.ts create mode 100644 app/react/portainer/environments/wizard/components/Option/Option.module.css create mode 100644 app/react/portainer/environments/wizard/components/Option/Option.tsx create mode 100644 app/react/portainer/environments/wizard/components/Option/index.ts create mode 100644 app/react/portainer/environments/wizard/index.ts diff --git a/api/http/handler/endpoints/endpoint_create.go b/api/http/handler/endpoints/endpoint_create.go index 90bcf3cc6..40367820b 100644 --- a/api/http/handler/endpoints/endpoint_create.go +++ b/api/http/handler/endpoints/endpoint_create.go @@ -187,6 +187,15 @@ func (handler *Handler) endpointCreate(w http.ResponseWriter, r *http.Request) * return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err} } + isUnique, err := handler.isNameUnique(payload.Name, 0) + if err != nil { + return httperror.InternalServerError("Unable to check if name is unique", err) + } + + if !isUnique { + return httperror.NewError(http.StatusConflict, "Name is not unique", nil) + } + endpoint, endpointCreationError := handler.createEndpoint(payload) if endpointCreationError != nil { return endpointCreationError diff --git a/api/http/handler/endpoints/endpoint_list.go b/api/http/handler/endpoints/endpoint_list.go index 1ce86a63d..60ff222a0 100644 --- a/api/http/handler/endpoints/endpoint_list.go +++ b/api/http/handler/endpoints/endpoint_list.go @@ -50,6 +50,7 @@ var endpointGroupNames map[portainer.EndpointGroupID]string // @param tagsPartialMatch query bool false "If true, will return environment(endpoint) which has one of tagIds, if false (or missing) will return only environments(endpoints) that has all the tags" // @param endpointIds query []int false "will return only these environments(endpoints)" // @param edgeDeviceFilter query string false "will return only these edge environments, none will return only regular edge environments" Enum("all", "trusted", "untrusted", "none") +// @param name query string false "will return only environments(endpoints) with this name" // @success 200 {array} portainer.Endpoint "Endpoints" // @failure 500 "Server error" // @router /endpoints [get] @@ -127,6 +128,11 @@ func (handler *Handler) endpointList(w http.ResponseWriter, r *http.Request) *ht filteredEndpoints = filterEndpointsByGroupIDs(filteredEndpoints, groupIDs) } + name, _ := request.RetrieveQueryParameter(r, "name", true) + if name != "" { + filteredEndpoints = filterEndpointsByName(filteredEndpoints, name) + } + edgeDeviceFilter, _ := request.RetrieveQueryParameter(r, "edgeDeviceFilter", false) if edgeDeviceFilter != "" { filteredEndpoints = filterEndpointsByEdgeDevice(filteredEndpoints, edgeDeviceFilter) @@ -465,3 +471,18 @@ func filteredEndpointsByIds(endpoints []portainer.Endpoint, ids []portainer.Endp return filteredEndpoints } + +func filterEndpointsByName(endpoints []portainer.Endpoint, name string) []portainer.Endpoint { + if name == "" { + return endpoints + } + + filteredEndpoints := make([]portainer.Endpoint, 0) + + for _, endpoint := range endpoints { + if endpoint.Name == name { + filteredEndpoints = append(filteredEndpoints, endpoint) + } + } + return filteredEndpoints +} diff --git a/api/http/handler/endpoints/endpoint_update.go b/api/http/handler/endpoints/endpoint_update.go index f11746fb6..8196d7ef3 100644 --- a/api/http/handler/endpoints/endpoint_update.go +++ b/api/http/handler/endpoints/endpoint_update.go @@ -88,7 +88,18 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * } if payload.Name != nil { - endpoint.Name = *payload.Name + name := *payload.Name + isUnique, err := handler.isNameUnique(name, endpoint.ID) + if err != nil { + return httperror.InternalServerError("Unable to check if name is unique", err) + } + + if !isUnique { + return httperror.NewError(http.StatusConflict, "Name is not unique", nil) + } + + endpoint.Name = name + } if payload.URL != nil { diff --git a/api/http/handler/endpoints/unique_name.go b/api/http/handler/endpoints/unique_name.go new file mode 100644 index 000000000..bad167d1b --- /dev/null +++ b/api/http/handler/endpoints/unique_name.go @@ -0,0 +1,18 @@ +package endpoints + +import portainer "github.com/portainer/portainer/api" + +func (handler *Handler) isNameUnique(name string, endpointID portainer.EndpointID) (bool, error) { + endpoints, err := handler.DataStore.Endpoint().Endpoints() + if err != nil { + return false, err + } + + for _, endpoint := range endpoints { + if endpoint.Name == name && (endpointID == 0 || endpoint.ID != endpointID) { + return false, nil + } + } + + return true, nil +} diff --git a/app/angulartics.matomo/analytics-services.ts b/app/angulartics.matomo/analytics-services.ts index 6141a4da6..dcc729630 100644 --- a/app/angulartics.matomo/analytics-services.ts +++ b/app/angulartics.matomo/analytics-services.ts @@ -1,5 +1,7 @@ import _ from 'lodash'; +import { useSettings } from '@/portainer/settings/queries'; + const categories = [ 'docker', 'kubernetes', @@ -61,6 +63,18 @@ export function push( } } +export function useAnalytics() { + const telemetryQuery = useSettings((settings) => settings.EnableTelemetry); + + return { trackEvent: handleTrackEvent }; + + function handleTrackEvent(...args: Parameters) { + if (telemetryQuery.data) { + trackEvent(...args); + } + } +} + export function trackEvent(action: string, properties: TrackEventProps) { /** * @description Logs an event with an event category (Videos, Music, Games...), an event diff --git a/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesDatatable/EdgeDevicesDatatableContainer.tsx b/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesDatatable/EdgeDevicesDatatableContainer.tsx index 275b76ce2..16f1a2181 100644 --- a/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesDatatable/EdgeDevicesDatatableContainer.tsx +++ b/app/edge/EdgeDevices/EdgeDevicesView/EdgeDevicesDatatable/EdgeDevicesDatatableContainer.tsx @@ -4,7 +4,7 @@ import { TableSettingsProvider, useTableSettings, } from '@/portainer/components/datatables/components/useTableSettings'; -import { useEnvironmentList } from '@/portainer/environments/queries'; +import { useEnvironmentList } from '@/portainer/environments/queries/useEnvironmentList'; import { Environment } from '@/portainer/environments/types'; import { useSearchBarState } from '@/portainer/components/datatables/components/SearchBar'; import { useDebounce } from '@/portainer/hooks/useDebounce'; @@ -92,7 +92,6 @@ function Loader({ children, storageKey }: LoaderProps) { search: debouncedSearchValue, ...pagination, }, - false, settings.autoRefreshRate * 1000 ); diff --git a/app/edge/EdgeDevices/WaitingRoomView/WaitingRoomView.tsx b/app/edge/EdgeDevices/WaitingRoomView/WaitingRoomView.tsx index 9e5d44ce1..02d0f8c6d 100644 --- a/app/edge/EdgeDevices/WaitingRoomView/WaitingRoomView.tsx +++ b/app/edge/EdgeDevices/WaitingRoomView/WaitingRoomView.tsx @@ -2,7 +2,7 @@ import { useRouter } from '@uirouter/react'; import { TableSettingsProvider } from '@/portainer/components/datatables/components/useTableSettings'; import { PageHeader } from '@/portainer/components/PageHeader'; -import { useEnvironmentList } from '@/portainer/environments/queries'; +import { useEnvironmentList } from '@/portainer/environments/queries/useEnvironmentList'; import { r2a } from '@/react-tools/react2angular'; import { DataTable } from './Datatable/Datatable'; diff --git a/app/portainer/__module.js b/app/portainer/__module.js index f3d3465fd..0e81f2394 100644 --- a/app/portainer/__module.js +++ b/app/portainer/__module.js @@ -344,26 +344,6 @@ angular }, }; - const wizard = { - name: 'portainer.wizard', - url: '/wizard', - views: { - 'content@': { - component: 'wizardView', - }, - }, - }; - - const wizardEndpoints = { - name: 'portainer.wizard.endpoints', - url: '/endpoints', - views: { - 'content@': { - component: 'wizardEndpoints', - }, - }, - }; - var initEndpoint = { name: 'portainer.init.endpoint', url: '/endpoint', @@ -529,8 +509,6 @@ angular $stateRegistryProvider.register(groupCreation); $stateRegistryProvider.register(home); $stateRegistryProvider.register(init); - $stateRegistryProvider.register(wizard); - $stateRegistryProvider.register(wizardEndpoints); $stateRegistryProvider.register(initEndpoint); $stateRegistryProvider.register(initAdmin); $stateRegistryProvider.register(registries); diff --git a/app/portainer/components/form-components/FileUpload/FileUploadField.stories.tsx b/app/portainer/components/form-components/FileUpload/FileUploadField.stories.tsx index 535097a67..66e990fda 100644 --- a/app/portainer/components/form-components/FileUpload/FileUploadField.stories.tsx +++ b/app/portainer/components/form-components/FileUpload/FileUploadField.stories.tsx @@ -22,5 +22,12 @@ function Example({ title }: Args) { } } - return ; + return ( + + ); } diff --git a/app/portainer/components/form-components/FileUpload/FileUploadField.test.tsx b/app/portainer/components/form-components/FileUpload/FileUploadField.test.tsx index dca222b94..fe287a991 100644 --- a/app/portainer/components/form-components/FileUpload/FileUploadField.test.tsx +++ b/app/portainer/components/form-components/FileUpload/FileUploadField.test.tsx @@ -5,7 +5,11 @@ import { FileUploadField } from './FileUploadField'; test('render should make the file button clickable and fire onChange event after click', async () => { const onClick = jest.fn(); const { findByText, findByLabelText } = render( - + ); const button = await findByText('test button'); diff --git a/app/portainer/components/form-components/FileUpload/FileUploadField.tsx b/app/portainer/components/form-components/FileUpload/FileUploadField.tsx index c742feabe..7d005eeeb 100644 --- a/app/portainer/components/form-components/FileUpload/FileUploadField.tsx +++ b/app/portainer/components/form-components/FileUpload/FileUploadField.tsx @@ -11,6 +11,7 @@ export interface Props { accept?: string; title?: string; required?: boolean; + inputId: string; } export function FileUploadField({ @@ -19,12 +20,14 @@ export function FileUploadField({ accept, title = 'Select a file', required = false, + inputId, }: Props) { const fileRef = createRef(); return (
) { return ( -
-
- +
+
+ {required && *} + + {tooltip && } + + +
{children}
{errors && ( -
+
{errors}
)} diff --git a/app/portainer/components/form-components/FormSection/FormSection.stories.tsx b/app/portainer/components/form-components/FormSection/FormSection.stories.tsx new file mode 100644 index 000000000..fcd78b593 --- /dev/null +++ b/app/portainer/components/form-components/FormSection/FormSection.stories.tsx @@ -0,0 +1,43 @@ +import { Meta, Story } from '@storybook/react'; + +import { FormSection } from './FormSection'; + +export default { + component: FormSection, + title: 'Components/Form/FormSection', +} as Meta; + +interface Args { + title: string; + content: string; +} + +function Template({ title, content }: Args) { + return {content}; +} + +const exampleContent = `Content + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam egestas turpis magna, + vel pretium dui rhoncus nec. Maecenas felis purus, consectetur non porta sit amet, + auctor sed sapien. Aliquam eu nunc felis. Pellentesque pulvinar velit id quam pellentesque, + nec imperdiet dui finibus. In blandit augue nibh, nec tincidunt nisi porttitor quis. + Nullam nec nibh maximus, consequat quam sed, dapibus purus. Donec facilisis commodo mi, in commodo augue molestie sed. + `; + +export const Example: Story = Template.bind({}); +Example.args = { + title: 'title', + content: exampleContent, +}; + +export function FoldableSection({ + title = 'title', + content = exampleContent, +}: Args) { + return ( + + {content} + + ); +} diff --git a/app/portainer/components/form-components/FormSection/FormSection.tsx b/app/portainer/components/form-components/FormSection/FormSection.tsx new file mode 100644 index 000000000..c833bcf39 --- /dev/null +++ b/app/portainer/components/form-components/FormSection/FormSection.tsx @@ -0,0 +1,39 @@ +import { PropsWithChildren, useState } from 'react'; + +import { FormSectionTitle } from '../FormSectionTitle'; + +interface Props { + title: string; + isFoldable?: boolean; +} + +export function FormSection({ + title, + children, + isFoldable = false, +}: PropsWithChildren) { + const [isExpanded, setIsExpanded] = useState(!isFoldable); + + return ( + <> + + {isFoldable && ( +