From f3ad97f07f6924c7f99fb7907f8d3bae99f12b63 Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Mon, 31 Oct 2022 15:04:41 +0530 Subject: [PATCH 01/44] THREESCALE-8443 prevent Emails being sent without a subject or body in reply to message --- .../admin/messages/inbox_controller.rb | 15 +++++++++----- .../admin/messages/inbox_controller_test.rb | 20 +++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/controllers/provider/admin/messages/inbox_controller.rb b/app/controllers/provider/admin/messages/inbox_controller.rb index 5ea00235c2..7d8e6d76ce 100644 --- a/app/controllers/provider/admin/messages/inbox_controller.rb +++ b/app/controllers/provider/admin/messages/inbox_controller.rb @@ -22,11 +22,16 @@ def reply reply = @message.reply reply.attributes = message_params - reply.save! - reply.deliver! - - flash[:notice] = 'Reply was sent.' - redirect_to action: :index + if reply.valid? + reply.save! + reply.deliver! + + flash[:notice] = 'Reply was sent.' + redirect_to action: :index + else + flash[:error] = reply.errors.full_messages.to_sentence + redirect_to provider_admin_messages_inbox_path(@message) + end end private diff --git a/test/functional/provider/admin/messages/inbox_controller_test.rb b/test/functional/provider/admin/messages/inbox_controller_test.rb index fda6a79655..fcec01e991 100644 --- a/test/functional/provider/admin/messages/inbox_controller_test.rb +++ b/test/functional/provider/admin/messages/inbox_controller_test.rb @@ -48,4 +48,24 @@ def test_index_system_message assert_select 'title', "Inbox - Index | Red Hat 3scale API Management" assert_select '#export-to-csv', false, 'Export all Messages' end + + test 'Prevent sending reply without subject' do + login_as(@admin) + reply = @message.reply + reply.update_attributes(body: 'Reply Body', subject: nil) + + MessageWorker.drain + assert msg = Message.last + assert_not_equal "Reply Body", msg.body + end + + test 'Allow sending reply with subject' do + login_as(@admin) + reply = @message.reply + reply.update_attributes(body: 'Reply Body', subject: 'Reply Subject') + + MessageWorker.drain + assert msg = Message.last + assert_equal "Reply Subject", msg.subject + end end From c0154ce5be585742dbd10fb15efa7d58fb96647c Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Mon, 31 Oct 2022 22:53:43 +0530 Subject: [PATCH 02/44] THREESCALE-8443 fixed code climate --- .../provider/admin/messages/inbox_controller.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/provider/admin/messages/inbox_controller.rb b/app/controllers/provider/admin/messages/inbox_controller.rb index 7d8e6d76ce..c6d5057265 100644 --- a/app/controllers/provider/admin/messages/inbox_controller.rb +++ b/app/controllers/provider/admin/messages/inbox_controller.rb @@ -23,11 +23,7 @@ def reply reply.attributes = message_params if reply.valid? - reply.save! - reply.deliver! - - flash[:notice] = 'Reply was sent.' - redirect_to action: :index + send_reply(reply) else flash[:error] = reply.errors.full_messages.to_sentence redirect_to provider_admin_messages_inbox_path(@message) @@ -43,4 +39,12 @@ def message_params def find_message @message = current_account.received_messages.find(params.require(:id)).decorate end + + def send_reply(reply) + reply.save! + reply.deliver! + + flash[:notice] = 'Reply was sent.' + redirect_to action: :index + end end From 2e182347f8fa9a172a3db5bd56d76b7962715134 Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Wed, 2 Nov 2022 15:38:44 +0530 Subject: [PATCH 03/44] THREESCALE-8443 removed bang which are not required --- app/controllers/provider/admin/messages/inbox_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/provider/admin/messages/inbox_controller.rb b/app/controllers/provider/admin/messages/inbox_controller.rb index c6d5057265..7396300796 100644 --- a/app/controllers/provider/admin/messages/inbox_controller.rb +++ b/app/controllers/provider/admin/messages/inbox_controller.rb @@ -41,8 +41,8 @@ def find_message end def send_reply(reply) - reply.save! - reply.deliver! + reply.save + reply.deliver flash[:notice] = 'Reply was sent.' redirect_to action: :index From ff3bd6ad8e2e84149b0223d56c689856376563a4 Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Wed, 2 Nov 2022 23:17:15 +0530 Subject: [PATCH 04/44] THREESCALE-8443 updated test cases --- .../admin/messages/inbox_controller_test.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/functional/provider/admin/messages/inbox_controller_test.rb b/test/functional/provider/admin/messages/inbox_controller_test.rb index fcec01e991..4e0a108e78 100644 --- a/test/functional/provider/admin/messages/inbox_controller_test.rb +++ b/test/functional/provider/admin/messages/inbox_controller_test.rb @@ -49,23 +49,23 @@ def test_index_system_message assert_select '#export-to-csv', false, 'Export all Messages' end - test 'Prevent sending reply without subject' do + test "creates valid reply" do login_as(@admin) - reply = @message.reply - reply.update_attributes(body: 'Reply Body', subject: nil) + post :reply, params: { message: { subject: "Valid Message", :body => "message with subject" }, id: @message.id } MessageWorker.drain - assert msg = Message.last - assert_not_equal "Reply Body", msg.body + msg = Message.last + assert "sent" msg.state + assert_equal "message with subject", msg.body end - test 'Allow sending reply with subject' do + test "not creates invalid message" do login_as(@admin) - reply = @message.reply - reply.update_attributes(body: 'Reply Body', subject: 'Reply Subject') + post :reply, params: { message: { subject: nil, body: "message with nil subject" }, id: @message.id } MessageWorker.drain - assert msg = Message.last - assert_equal "Reply Subject", msg.subject + msg = Message.last + assert_not_equal "message with nil subject", msg.body end + end From 149a29aa9c872cee8dff0b59753f6ab635701939 Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Thu, 3 Nov 2022 16:46:37 +0530 Subject: [PATCH 05/44] THREESCALE-8443 fixed a comma --- .../functional/provider/admin/messages/inbox_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/provider/admin/messages/inbox_controller_test.rb b/test/functional/provider/admin/messages/inbox_controller_test.rb index 4e0a108e78..d5f09e49c7 100644 --- a/test/functional/provider/admin/messages/inbox_controller_test.rb +++ b/test/functional/provider/admin/messages/inbox_controller_test.rb @@ -55,7 +55,7 @@ def test_index_system_message MessageWorker.drain msg = Message.last - assert "sent" msg.state + assert "sent", msg.state assert_equal "message with subject", msg.body end From 2028c613de09c73de06d7c31406478d967976e37 Mon Sep 17 00:00:00 2001 From: "Aleksandar N. Kostadinov" Date: Thu, 3 Nov 2022 17:06:08 +0200 Subject: [PATCH 06/44] fail if setup commands fail related to THREESCALE-8896 --- openshift/system/entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openshift/system/entrypoint.sh b/openshift/system/entrypoint.sh index d8913fc18c..1986cdd818 100755 --- a/openshift/system/entrypoint.sh +++ b/openshift/system/entrypoint.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + EXTRA_CONFIGS_DIR=${EXTRA_CONFIGS_DIR:-/opt/system-extra-configs} BASE_CONFIGS_DIR=${BASE_CONFIGS:-/opt/system/config} From 3c56af9c05677e780ef4a87d30a333bc81bc378b Mon Sep 17 00:00:00 2001 From: Nidhi Soni <84672731+nidhi-soni1104@users.noreply.github.com> Date: Mon, 7 Nov 2022 14:31:07 +0530 Subject: [PATCH 07/44] Update test/functional/provider/admin/messages/inbox_controller_test.rb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joan Lledó --- .../functional/provider/admin/messages/inbox_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/provider/admin/messages/inbox_controller_test.rb b/test/functional/provider/admin/messages/inbox_controller_test.rb index d5f09e49c7..b52022ece0 100644 --- a/test/functional/provider/admin/messages/inbox_controller_test.rb +++ b/test/functional/provider/admin/messages/inbox_controller_test.rb @@ -51,7 +51,7 @@ def test_index_system_message test "creates valid reply" do login_as(@admin) - post :reply, params: { message: { subject: "Valid Message", :body => "message with subject" }, id: @message.id } + post :reply, params: { message: { subject: "Valid Message", body: "message with subject" }, id: @message.id } MessageWorker.drain msg = Message.last From 4aecf7af50917a328642fc7807f1f7980eb175d3 Mon Sep 17 00:00:00 2001 From: Nidhi Soni Date: Mon, 7 Nov 2022 16:13:35 +0530 Subject: [PATCH 08/44] THREESCALE-8443 Fix test assertions --- .../admin/messages/inbox_controller_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/functional/provider/admin/messages/inbox_controller_test.rb b/test/functional/provider/admin/messages/inbox_controller_test.rb index b52022ece0..0e7e3c52c6 100644 --- a/test/functional/provider/admin/messages/inbox_controller_test.rb +++ b/test/functional/provider/admin/messages/inbox_controller_test.rb @@ -49,23 +49,23 @@ def test_index_system_message assert_select '#export-to-csv', false, 'Export all Messages' end - test "creates valid reply" do + test 'creates valid reply' do login_as(@admin) post :reply, params: { message: { subject: "Valid Message", body: "message with subject" }, id: @message.id } MessageWorker.drain msg = Message.last - assert "sent", msg.state - assert_equal "message with subject", msg.body + assert_equal flash[:notice], 'Reply was sent.' + assert 'sent', msg.state + assert_equal 'message with subject', msg.body end - test "not creates invalid message" do + test 'not creates invalid message' do login_as(@admin) - post :reply, params: { message: { subject: nil, body: "message with nil subject" }, id: @message.id } + post :reply, params: { message: { subject: nil, body: 'message with nil subject' }, id: @message.id } MessageWorker.drain - msg = Message.last - assert_not_equal "message with nil subject", msg.body + msg = Message.find_by(id: @message.message_id) + assert_not_equal 'message with nil subject', msg.body end - end From 30b5f9f8b0a5898a8ee1e4d0b4af1f951a39154c Mon Sep 17 00:00:00 2001 From: Jose Miguel Gallas Olmedo Date: Wed, 9 Nov 2022 15:34:26 +0100 Subject: [PATCH 09/44] =?UTF-8?q?=E2=9A=B0=EF=B8=8F=20Flow=20to=20TS=20(#3?= =?UTF-8?q?054)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🏷️ ⚰️ migrate Flow to Typescript Co-authored-by: lvillen --- .babelrc | 24 +- .circleci/config.yml | 19 +- .codeclimate.yml | 5 +- .dockerignore | 2 - .eslintignore | 38 +- .eslintrc | 197 +- .flowconfig | 22 - .gitignore | 3 +- app/javascript/packs/ChangePassword.js | 8 - app/javascript/packs/LoginPage.js | 13 - app/javascript/packs/OAS3Autocomplete.js | 110 - app/javascript/packs/PF4Styles/base.js | 1 - app/javascript/packs/RequestPasswordPage.js | 12 - app/javascript/packs/SignUpPage.js | 17 - app/javascript/packs/StripeForm.js | 15 - app/javascript/packs/active_docs.js | 16 - app/javascript/packs/active_docs.ts | 18 + ..._backend_usage.js => add_backend_usage.ts} | 14 +- app/javascript/packs/api_selector.js | 11 - app/javascript/packs/api_selector.ts | 23 + ..._index.js => backend_api_metrics_index.ts} | 10 +- ...nd_apis_index.js => backend_apis_index.ts} | 12 +- app/javascript/packs/backends_used_list.js | 22 - app/javascript/packs/backends_used_list.ts | 20 + .../packs/braintree_customer_form.js | 35 - .../packs/braintree_customer_form.ts | 38 + app/javascript/packs/change_password.ts | 21 + ...e_plan_select.js => change_plan_select.ts} | 14 +- .../packs/{dashboard.js => dashboard.ts} | 0 ...widget.js => dashboard_backends_widget.ts} | 11 +- .../packs/dashboard_products_widget.js | 16 - .../packs/dashboard_products_widget.ts | 23 + ...n_selector.js => default_plan_selector.ts} | 16 +- .../email_configurations/{edit.js => edit.ts} | 6 +- .../{index.js => index.ts} | 12 +- .../email_configurations/{new.js => new.ts} | 6 +- app/javascript/packs/inlineChart.js | 23 - app/javascript/packs/inline_chart.tsx | 32 + app/javascript/packs/invoice_payment.js | 87 - app/javascript/packs/invoice_payment.ts | 96 + .../packs/{load_stripe.js => load_stripe.ts} | 1 + app/javascript/packs/login_page.ts | 24 + app/javascript/packs/navigation.js | 42 - app/javascript/packs/navigation.ts | 42 + ...{new_application.js => new_application.ts} | 18 +- app/javascript/packs/new_mapping_rule.js | 25 - app/javascript/packs/new_mapping_rule.ts | 23 + app/javascript/packs/new_service.js | 9 - app/javascript/packs/new_service.ts | 18 + app/javascript/packs/permissions.js | 17 - app/javascript/packs/permissions.ts | 19 + .../{plans-metrics.js => plans_metrics.ts} | 13 +- app/javascript/packs/plans_table.js | 28 - app/javascript/packs/plans_table.ts | 26 + .../packs/{policies.js => policies.ts} | 5 +- ...rics_index.js => product_metrics_index.ts} | 10 +- app/javascript/packs/products_index.js | 24 - app/javascript/packs/products_index.ts | 22 + app/javascript/packs/products_used_list.js | 22 - app/javascript/packs/products_used_list.ts | 20 + .../{providerStats.js => provider_stats.ts} | 3 +- .../{container.js => container.ts} | 11 +- app/javascript/packs/request_password_page.ts | 17 + app/javascript/packs/service_active_docs.js | 18 - app/javascript/packs/service_active_docs.ts | 26 + .../packs/{services.js => services.ts} | 0 .../packs/{settings.js => settings.ts} | 0 app/javascript/packs/settingsPageStyles.js | 1 - app/javascript/packs/settings_page_styles.ts | 2 + app/javascript/packs/sign_up_page.ts | 22 + app/javascript/packs/{stats.js => stats.ts} | 3 +- app/javascript/packs/stripe_form.ts | 24 + ...opover.js => system_name_input_popover.ts} | 6 +- .../{validateSignup.js => validate_signup.ts} | 33 +- app/javascript/packs/vertical_nav.js | 22 - app/javascript/packs/vertical_nav.ts | 20 + ...d_backend_api.js => wizard_backend_api.ts} | 14 +- .../src/ActiveDocs/OAS3Autocomplete.ts | 122 + ...{AddBackendForm.jsx => AddBackendForm.tsx} | 80 +- .../{BackendSelect.jsx => BackendSelect.tsx} | 63 +- .../components/DescriptionInput.jsx | 27 - .../components/DescriptionInput.tsx | 28 + .../src/BackendApis/components/IndexPage.jsx | 130 - .../src/BackendApis/components/IndexPage.tsx | 102 + .../{NameInput.jsx => NameInput.tsx} | 22 +- ...{NewBackendForm.jsx => NewBackendForm.tsx} | 66 +- .../components/NewBackendModal.jsx | 77 - .../components/NewBackendModal.tsx | 80 + .../{PathInput.jsx => PathInput.tsx} | 30 +- ...ointInput.jsx => PrivateEndpointInput.tsx} | 32 +- ...dListCard.jsx => ProductsUsedListCard.tsx} | 31 +- ...ystemNameInput.jsx => SystemNameInput.tsx} | 22 +- app/javascript/src/BackendApis/index.js | 13 - app/javascript/src/BackendApis/types.js | 16 - app/javascript/src/BackendApis/types.ts | 14 + .../components/ChangePassword.jsx | 96 - .../components/ChangePassword.tsx | 99 + ...sswordHooks.jsx => ChangePasswordHooks.ts} | 89 +- app/javascript/src/ChangePassword/index.jsx | 4 - ...ompactListCard.jsx => CompactListCard.tsx} | 53 +- .../src/Common/components/FancySelect.jsx | 124 - .../src/Common/components/FancySelect.tsx | 117 + .../src/Common/components/HelperText.jsx | 36 - .../src/Common/components/HelperText.tsx | 19 + .../src/Common/components/MicroPagination.jsx | 34 - .../src/Common/components/MicroPagination.tsx | 36 + .../{NoMatchFound.jsx => NoMatchFound.tsx} | 30 +- .../src/Common/components/Pagination.tsx | 41 + .../src/Common/components/Select.jsx | 105 - .../src/Common/components/Select.tsx | 103 + ...electWithModal.jsx => SelectWithModal.tsx} | 129 +- .../src/Common/components/Spinner.jsx | 23 - .../src/Common/components/Spinner.tsx | 17 + .../Common/components/SystemNamePopover.jsx | 24 - .../Common/components/SystemNamePopover.tsx | 25 + .../{TableModal.jsx => TableModal.tsx} | 125 +- .../{ToolbarSearch.jsx => ToolbarSearch.tsx} | 80 +- ...rDefinedField.jsx => UserDefinedField.tsx} | 53 +- app/javascript/src/Common/index.js | 14 - .../{ajax-widget.jsx => ajax-widget.ts} | 4 +- app/javascript/src/Dashboard/chart.jsx | 92 - app/javascript/src/Dashboard/chart.ts | 98 + ...PIDataListItem.jsx => APIDataListItem.tsx} | 71 +- ...{BackendsWidget.jsx => BackendsWidget.tsx} | 64 +- ...{ProductsWidget.jsx => ProductsWidget.tsx} | 64 +- .../src/Dashboard/{index.jsx => index.ts} | 7 +- .../components/EditPage.jsx | 49 - .../components/EditPage.tsx | 50 + .../components/EmailConfigurationForm.jsx | 111 - .../components/EmailConfigurationForm.tsx | 112 + .../components/EmailConfigurationsTable.jsx | 130 - .../components/EmailConfigurationsTable.tsx | 101 + .../{IndexPage.jsx => IndexPage.tsx} | 25 +- .../components/NewPage.jsx | 48 - .../components/NewPage.tsx | 49 + .../{EmailInput.jsx => EmailInput.tsx} | 35 +- .../{PasswordInput.jsx => PasswordInput.tsx} | 37 +- ...epeatInput.jsx => PasswordRepeatInput.tsx} | 42 +- .../{UserNameInput.jsx => UserNameInput.tsx} | 35 +- .../components/form-fields/index.js | 6 - .../src/EmailConfigurations/types.js | 24 - .../src/EmailConfigurations/types.ts | 23 + app/javascript/src/Logic/BuyerLogic.js | 22 - app/javascript/src/Logic/BuyerLogic.ts | 16 + app/javascript/src/Logic/index.js | 3 - .../src/LoginPage/LoginPageWrapper.jsx | 106 - .../src/LoginPage/LoginPageWrapper.tsx | 92 + .../src/LoginPage/RequestPasswordWrapper.jsx | 41 - .../src/LoginPage/RequestPasswordWrapper.tsx | 43 + .../src/LoginPage/SignupPageWrapper.jsx | 32 - .../src/LoginPage/SignupPageWrapper.tsx | 30 + app/javascript/src/LoginPage/index.js | 14 - .../loginForms/AuthenticationProviders.jsx | 41 - .../loginForms/AuthenticationProviders.tsx | 37 + .../LoginPage/loginForms/FlashMessages.jsx | 23 - .../LoginPage/loginForms/FlashMessages.tsx | 24 + .../loginForms/ForgotCredentials.jsx | 11 - .../loginForms/ForgotCredentials.tsx | 15 + .../src/LoginPage/loginForms/FormGroups.jsx | 101 - .../src/LoginPage/loginForms/FormGroups.tsx | 106 + .../src/LoginPage/loginForms/HiddenInputs.jsx | 18 - .../src/LoginPage/loginForms/HiddenInputs.tsx | 17 + .../LoginPage/loginForms/Login3scaleForm.jsx | 116 - .../LoginPage/loginForms/Login3scaleForm.tsx | 118 + .../loginForms/RequestPasswordForm.jsx | 78 - .../loginForms/RequestPasswordForm.tsx | 81 + .../src/LoginPage/loginForms/SignupForm.jsx | 141 - .../src/LoginPage/loginForms/SignupForm.tsx | 136 + .../src/LoginPage/utils/formValidation.js | 38 - .../src/LoginPage/utils/formValidation.ts | 36 + .../components/HttpMethodSelect.jsx | 47 - .../components/HttpMethodSelect.tsx | 51 + ...rementByInput.jsx => IncrementByInput.tsx} | 27 +- .../components/IsLastCheckbox.jsx | 28 - .../components/IsLastCheckbox.tsx | 25 + .../{MetricInput.jsx => MetricInput.tsx} | 94 +- .../components/NewMappingRule.jsx | 112 - .../components/NewMappingRule.tsx | 112 + .../MappingRules/components/PatternInput.jsx | 37 - .../MappingRules/components/PatternInput.tsx | 39 + .../MappingRules/components/PositionInput.jsx | 30 - .../MappingRules/components/PositionInput.tsx | 32 + ...irectUrlInput.jsx => RedirectUrlInput.tsx} | 24 +- app/javascript/src/MappingRules/index.js | 10 - .../components/BackendAPIIndexPage.jsx | 60 - .../components/BackendAPIIndexPage.tsx | 56 + .../{IndexPage.jsx => IndexPage.tsx} | 62 +- .../src/Metrics/components/MetricsTable.jsx | 137 - .../src/Metrics/components/MetricsTable.tsx | 98 + .../Metrics/components/ProductIndexPage.jsx | 62 - .../Metrics/components/ProductIndexPage.tsx | 58 + app/javascript/src/Metrics/index.js | 8 - .../src/Metrics/types/{index.js => index.ts} | 2 - .../ActiveMenuTitle.scss | 0 ...ctiveMenuTitle.jsx => ActiveMenuTitle.tsx} | 23 +- .../ContextSelector.scss | 0 ...ontextSelector.jsx => ContextSelector.tsx} | 69 +- .../src/Navigation/components/VerticalNav.jsx | 67 - .../{styles => components}/VerticalNav.scss | 0 .../src/Navigation/components/VerticalNav.tsx | 73 + ...le_navigation.jsx => toggle_navigation.ts} | 13 +- .../components/ApplicationPlanSelect.jsx | 49 - .../components/ApplicationPlanSelect.tsx | 48 + .../{BuyerSelect.jsx => BuyerSelect.tsx} | 53 +- ...icationForm.jsx => NewApplicationForm.tsx} | 152 +- .../{ProductSelect.jsx => ProductSelect.tsx} | 53 +- ...cePlanSelect.jsx => ServicePlanSelect.tsx} | 58 +- .../data/{Buyers.js => Buyers.ts} | 4 +- .../data/{Products.js => Products.ts} | 4 +- .../src/NewApplication/data/index.js | 4 - app/javascript/src/NewApplication/index.js | 7 - app/javascript/src/NewApplication/types.js | 38 - app/javascript/src/NewApplication/types.ts | 31 + .../components/FormElements/ErrorMessage.jsx | 15 - .../components/FormElements/ErrorMessage.tsx | 13 + .../components/FormElements/FormWrapper.jsx | 39 - .../components/FormElements/FormWrapper.tsx | 43 + .../HiddenServiceDiscoveryInput.jsx | 13 - .../HiddenServiceDiscoveryInput.tsx | 12 + .../components/FormElements/Label.jsx | 17 - .../components/FormElements/Label.tsx | 15 + .../components/FormElements/Select.jsx | 30 - .../components/FormElements/Select.tsx | 29 + .../ServiceDiscoveryListItems.jsx | 71 - .../ServiceDiscoveryListItems.tsx | 73 + .../FormElements/ServiceManualListItems.jsx | 48 - .../FormElements/ServiceManualListItems.tsx | 53 + .../components/FormElements/index.jsx | 9 - .../NewService/components/NewServiceForm.jsx | 55 - .../NewService/components/NewServiceForm.tsx | 59 + .../components/ServiceDiscoveryForm.jsx | 60 - .../components/ServiceDiscoveryForm.tsx | 60 + .../components/ServiceManualForm.jsx | 32 - .../components/ServiceManualForm.tsx | 31 + ...ceSourceForm.jsx => ServiceSourceForm.tsx} | 43 +- app/javascript/src/NewService/index.jsx | 9 - app/javascript/src/NewService/types/index.js | 24 - app/javascript/src/NewService/types/index.ts | 22 + ....jsx => BraintreeBillingAddressFields.tsx} | 73 +- .../braintree/BraintreeCardFields.jsx | 55 - .../braintree/BraintreeCardFields.tsx | 53 + .../braintree/BraintreeForm.jsx | 150 - .../braintree/BraintreeForm.tsx | 166 + .../braintree/BraintreeFormWrapper.jsx | 12 - .../braintree/BraintreeSubmitFields.jsx | 23 - .../braintree/BraintreeSubmitFields.tsx | 26 + ...UserFields.jsx => BraintreeUserFields.tsx} | 28 +- .../braintree/{braintree.js => braintree.ts} | 53 +- .../braintree/components/Input.jsx | 19 - .../braintree/components/Input.tsx | 29 + .../braintree/components/Label.jsx | 16 - .../braintree/components/Label.tsx | 19 + .../braintree/components/ListItem.jsx | 18 - .../braintree/components/ListItem.tsx | 13 + .../src/PaymentGateways/braintree/types.js | 69 - .../src/PaymentGateways/braintree/types.ts | 20 + app/javascript/src/PaymentGateways/index.js | 15 - ...{StripeCardForm.jsx => StripeCardForm.tsx} | 130 +- .../stripe/components/StripeFormWrapper.jsx | 44 - .../StripeFormWrapper.scss} | 0 .../stripe/components/StripeFormWrapper.tsx | 49 + ...electCard.jsx => ChangePlanSelectCard.tsx} | 51 +- ...lectCard.jsx => DefaultPlanSelectCard.tsx} | 58 +- .../src/Plans/components/PlansTable.jsx | 119 - .../src/Plans/components/PlansTable.tsx | 94 + .../src/Plans/components/PlansTableCard.jsx | 130 - .../src/Plans/components/PlansTableCard.tsx | 130 + app/javascript/src/Plans/index.js | 4 - .../Policies/actions/OriginalPolicyChain.jsx | 8 - .../Policies/actions/OriginalPolicyChain.ts | 9 + .../src/Policies/actions/PolicyChain.jsx | 63 - .../src/Policies/actions/PolicyChain.ts | 83 + .../{PolicyConfig.jsx => PolicyConfig.ts} | 7 +- .../src/Policies/actions/PolicyRegistry.jsx | 28 - .../src/Policies/actions/PolicyRegistry.ts | 37 + .../src/Policies/actions/ThunkActions.jsx | 121 - .../src/Policies/actions/ThunkActions.ts | 121 + .../src/Policies/actions/UISettings.jsx | 18 - .../src/Policies/actions/UISettings.ts | 25 + .../Policies/actions/{index.jsx => index.ts} | 2 - .../src/Policies/components/HeaderButton.jsx | 36 - .../src/Policies/components/HeaderButton.tsx | 40 + ...{PoliciesWidget.jsx => PoliciesWidget.tsx} | 51 +- .../src/Policies/components/PolicyChain.jsx | 83 - .../src/Policies/components/PolicyChain.tsx | 97 + ...enInput.jsx => PolicyChainHiddenInput.tsx} | 18 +- .../{PolicyConfig.jsx => PolicyConfig.tsx} | 48 +- ...{PolicyRegistry.jsx => PolicyRegistry.tsx} | 27 +- .../src/Policies/components/PolicyTile.jsx | 26 - .../src/Policies/components/PolicyTile.tsx | 26 + .../src/Policies/components/Root.jsx | 25 - .../src/Policies/components/Root.tsx | 17 + app/javascript/src/Policies/index.jsx | 33 - app/javascript/src/Policies/index.tsx | 24 + .../src/Policies/middleware/PolicyChain.jsx | 67 - .../src/Policies/middleware/PolicyChain.ts | 86 + .../Policies/reducers/OriginalPolicyChain.jsx | 18 - .../Policies/reducers/OriginalPolicyChain.ts | 18 + .../{PolicyChain.jsx => PolicyChain.ts} | 16 +- .../{PolicyConfig.jsx => PolicyConfig.ts} | 6 +- .../src/Policies/reducers/PolicyRegistry.jsx | 19 - .../src/Policies/reducers/PolicyRegistry.ts | 19 + .../{UISettings.jsx => UISettings.ts} | 7 +- .../Policies/reducers/{index.jsx => index.ts} | 3 - .../{initialState.jsx => initialState.ts} | 4 - .../{configureStore.jsx => configureStore.ts} | 12 +- app/javascript/src/Policies/store/index.jsx | 3 - app/javascript/src/Policies/types/Actions.jsx | 59 - app/javascript/src/Policies/types/Actions.ts | 50 + .../src/Policies/types/Policies.jsx | 31 - app/javascript/src/Policies/types/Policies.ts | 31 + app/javascript/src/Policies/types/State.jsx | 22 - app/javascript/src/Policies/types/State.ts | 20 + app/javascript/src/Policies/types/index.jsx | 18 - app/javascript/src/Policies/types/index.ts | 13 + .../src/Policies/{util.jsx => util.ts} | 19 +- ...-public-path.js => webpack-public-path.ts} | 1 + ...dListCard.jsx => BackendsUsedListCard.tsx} | 31 +- .../src/Products/components/IndexPage.jsx | 132 - .../src/Products/components/IndexPage.tsx | 102 + app/javascript/src/Products/index.js | 4 - app/javascript/src/Products/types.js | 19 - app/javascript/src/Products/types.ts | 15 + ...tContainer.jsx => QuickStartContainer.tsx} | 42 +- .../templates/{index.js => index.ts} | 2 - .../src/QuickStarts/utils/progressTracker.js | 13 - .../src/QuickStarts/utils/progressTracker.ts | 12 + ...sExtension.js => replaceLinksExtension.ts} | 12 +- .../src/Settings/authentication-widget.jsx | 61 - .../src/Settings/authentication-widget.ts | 81 + .../AuthenticationSettingsFieldset.jsx | 47 - .../AuthenticationSettingsFieldset.tsx | 48 + .../components/Common/FormCollection.jsx | 24 - .../components/Common/FormCollection.tsx | 27 + .../components/Common/FormFieldset.jsx | 37 - .../components/Common/FormFieldset.tsx | 17 + .../Settings/components/Common/FormLegend.jsx | 23 - .../Settings/components/Common/FormLegend.tsx | 12 + .../{RadioFieldset.jsx => RadioFieldset.tsx} | 34 +- .../components/Common/SelectGroup.jsx | 44 - .../components/Common/SelectGroup.tsx | 41 + ...{TextInputGroup.jsx => TextInputGroup.tsx} | 25 +- .../components/Common/TypeItemCombo.jsx | 26 - .../components/Common/TypeItemCombo.tsx | 27 + .../src/Settings/components/Common/index.jsx | 9 - .../src/Settings/components/Form.jsx | 65 - .../src/Settings/components/Form.tsx | 88 + .../src/Settings/components/OidcFieldset.jsx | 53 - .../src/Settings/components/OidcFieldset.tsx | 65 + .../Settings/{defaults.jsx => defaults.ts} | 35 +- app/javascript/src/Settings/index.jsx | 21 - app/javascript/src/Settings/types/index.jsx | 50 - app/javascript/src/Settings/types/index.ts | 31 + .../inlinechart/{index.jsx => index.tsx} | 53 +- app/javascript/src/Stats/stats.d.ts | 1 + app/javascript/src/Types/Api.jsx | 8 - app/javascript/src/Types/Api.ts | 6 + app/javascript/src/Types/FlashMessages.jsx | 6 - app/javascript/src/Types/FlashMessages.ts | 4 + app/javascript/src/Types/NavigationTypes.jsx | 20 - app/javascript/src/Types/NavigationTypes.ts | 1 + app/javascript/src/Types/Signup.jsx | 28 - app/javascript/src/Types/Signup.ts | 30 + app/javascript/src/Types/SwaggerTypes.jsx | 70 - app/javascript/src/Types/SwaggerTypes.ts | 4 + app/javascript/src/Types/custom.d.ts | 58 + app/javascript/src/Types/globals.d.ts | 35 + app/javascript/src/Types/index.js | 60 - app/javascript/src/Types/index.ts | 61 + app/javascript/src/Types/libs/libdefs.js | 27 - ...turesFieldset.jsx => FeaturesFieldset.tsx} | 108 +- ...ermissionsForm.jsx => PermissionsForm.tsx} | 57 +- .../src/Users/components/RoleRadioGroup.jsx | 62 - .../src/Users/components/RoleRadioGroup.tsx | 72 + ...vicesFieldset.jsx => ServicesFieldset.tsx} | 70 +- app/javascript/src/Users/types/index.jsx | 13 - app/javascript/src/Users/types/index.ts | 5 + .../src/Users/utils/{index.jsx => index.ts} | 21 +- app/javascript/src/services/index.jsx | 20 - app/javascript/src/services/index.ts | 19 + app/javascript/src/services/migrate.jsx | 47 - app/javascript/src/services/migrate.ts | 40 + app/javascript/src/utilities/CSRFToken.jsx | 24 - app/javascript/src/utilities/CSRFToken.tsx | 22 + .../src/utilities/{ajax.js => ajax.ts} | 23 +- app/javascript/src/utilities/alert.js | 5 - .../src/utilities/confirm-dialog.jsx | 5 - .../src/utilities/confirm-dialog.ts | 3 + ...ReactWrapper.jsx => createReactWrapper.ts} | 7 +- .../utilities/{fetchData.js => fetchData.ts} | 4 +- app/javascript/src/utilities/flash.ts | 3 + app/javascript/src/utilities/index.js | 15 - .../{isActiveTab.js => isActiveTab.ts} | 4 +- .../{json-utils.jsx => json-utils.ts} | 11 +- .../src/utilities/paginateCollection.js | 12 - .../src/utilities/paginateCollection.ts | 14 + .../src/utilities/patternfly-utils.jsx | 58 - .../src/utilities/patternfly-utils.tsx | 65 + app/javascript/src/utilities/test-utils.js | 87 - app/javascript/src/utilities/test-utils.ts | 98 + app/javascript/src/utilities/toggle.jsx | 97 - app/javascript/src/utilities/toggle.ts | 107 + ...{useClickOutside.js => useClickOutside.ts} | 11 +- .../src/utilities/useSearchInputEffect.js | 40 - .../src/utilities/useSearchInputEffect.ts | 39 + app/views/api/plans/_metrics.html.erb | 2 +- app/views/layouts/provider.html.slim | 2 +- app/views/payment_gateways/_stripe.html.erb | 2 +- .../backend_apis/stats/usage/index.html.slim | 2 +- .../provider/invitee_signups/show.html.erb | 2 +- app/views/provider/passwords/reset.html.slim | 2 +- app/views/provider/passwords/show.html.erb | 2 +- app/views/provider/sessions/new.html.slim | 2 +- app/views/stats/_inlinechart.html.erb | 2 +- app/views/stats/applications/show.html.slim | 2 +- app/views/stats/days/index.html.slim | 2 +- app/views/stats/response_codes/show.html.slim | 2 +- app/views/stats/usage/hours.html.slim | 2 +- app/views/stats/usage/index.html.slim | 2 +- .../stats/usage/top_applications.html.slim | 2 +- config/webpack/development.js | 3 +- config/webpack/environment.js | 11 +- config/webpack/production.js | 4 + config/webpacker.yml | 1 + doc/licenses/licenses.xml | 3518 ++-------- eslint-naming-conventions.json | 22 + jest.config.js | 193 +- .../developer_portal/signup/show.html.liquid | 4 +- .../lib/liquid/filters/rails_helpers.rb | 2 +- lib/generators/react_page/USAGE | 13 - .../react_page/react_page_generator.rb | 122 - package.json | 80 +- spec/javascripts/.eslintrc | 19 + ...lete.spec.jsx => OAS3Autocomplete.spec.ts} | 17 +- .../components/AddBackendForm.spec.jsx | 102 - .../components/AddBackendForm.spec.tsx | 102 + ...Select.spec.jsx => BackendSelect.spec.tsx} | 25 +- ...put.spec.jsx => DescriptionInput.spec.tsx} | 19 +- ...{IndexPage.spec.jsx => IndexPage.spec.tsx} | 18 +- .../BackendApis/components/NameInput.spec.jsx | 35 - .../BackendApis/components/NameInput.spec.tsx | 33 + .../components/NewBackendForm.spec.jsx | 174 - .../components/NewBackendForm.spec.tsx | 173 + ...odal.spec.jsx => NewBackendModal.spec.tsx} | 21 +- ...{PathInput.spec.jsx => PathInput.spec.tsx} | 19 +- .../components/PrivateEndpointInput.spec.jsx | 35 - .../components/PrivateEndpointInput.spec.tsx | 29 + .../components/ProductsUsedList.spec.jsx | 67 - .../components/ProductsUsedList.spec.tsx | 63 + ...nput.spec.jsx => SystemNameInput.spec.tsx} | 19 +- ...sword.spec.jsx => ChangePassword.spec.tsx} | 12 +- .../ChangePassword.spec.jsx.snap | 16 +- .../ChangePassword.spec.tsx.snap | 926 +++ ...Card.spec.jsx => CompactListCard.spec.tsx} | 30 +- ...cySelect.spec.jsx => FancySelect.spec.tsx} | 45 +- ...ieldset.spec.jsx => FormFieldset.spec.tsx} | 6 +- ...ormLegend.spec.jsx => FormLegend.spec.tsx} | 12 +- .../Common/components/HelperText.spec.tsx | 18 + ...tion.spec.jsx => MicroPagination.spec.tsx} | 33 +- .../Common/components/NoMatchFound.spec.jsx | 40 - .../Common/components/NoMatchFound.spec.tsx | 40 + .../{Select.spec.jsx => Select.spec.tsx} | 28 +- ...odal.spec.jsx => SelectWithModal.spec.tsx} | 60 +- .../Common/components/Spinner.spec.tsx | 17 + .../components/SystemNamePopover.spec.tsx | 10 + ...ableModal.spec.jsx => TableModal.spec.tsx} | 33 +- .../Common/components/ToolbarSearch.spec.jsx | 36 - .../Common/components/ToolbarSearch.spec.tsx | 31 + ...ect.spec.jsx => UserDefinedField.spec.tsx} | 26 +- ...ec.jsx.snap => FormFieldset.spec.tsx.snap} | 0 ...spec.jsx.snap => FormLegend.spec.tsx.snap} | 0 .../__snapshots__/SuperSelect.spec.jsx.snap | 3 - .../{chart.spec.js => chart.spec.tsx} | 0 .../components/APIDataListItem.spec.tsx | 23 + .../components/BackendsWidget.spec.tsx | 18 + .../components/ProductsWidget.spec.tsx | 18 + .../{EditPage.spec.jsx => EditPage.spec.tsx} | 17 +- ...ec.jsx => EmailConfigurationForm.spec.tsx} | 39 +- ....jsx => EmailConfigurationsTable.spec.tsx} | 9 +- ...{IndexPage.spec.jsx => IndexPage.spec.tsx} | 17 +- .../{NewPage.spec.jsx => NewPage.spec.tsx} | 13 +- ...mailInput.spec.jsx => EmailInput.spec.tsx} | 11 +- ...dInput.spec.jsx => PasswordInput.spec.tsx} | 11 +- ....spec.jsx => PasswordRepeatInput.spec.tsx} | 13 +- ...eInput.spec.jsx => UserNameInput.spec.tsx} | 11 +- ...uyerLogic.spec.jsx => BuyerLogic.spec.tsx} | 17 +- .../LoginPage/ForgotCredentials.spec.jsx | 15 - ...per.spec.jsx => LoginPageWrapper.spec.tsx} | 26 +- ...er.spec.jsx => SignupPageWrapper.spec.tsx} | 19 +- ...x.snap => ForgotCredentials.spec.tsx.snap} | 0 ...sx.snap => LoginPageWrapper.spec.tsx.snap} | 196 +- .../RequestPasswordForm.spec.jsx.snap | 410 -- .../RequestPasswordForm.spec.tsx.snap | 202 + .../AuthenticationProviders.spec.tsx} | 27 +- .../FlashMessages.spec.tsx} | 13 +- .../loginForms/ForgotCredentials.spec.tsx | 14 + .../FormGroups.spec.tsx} | 61 +- .../HiddenInputs.spec.tsx} | 7 +- .../Login3scaleForm.spec.tsx} | 63 +- .../RequestPasswordForm.spec.tsx} | 37 +- .../SignupForm.spec.tsx} | 206 +- .../ForgotCredentials.spec.tsx.snap | 19 + .../RequestPasswordForm.spec.tsx.snap | 209 + .../LoginPage/utils/formValidation.spec.ts | 24 + .../MappingRules/PatternInput.spec.jsx | 24 - .../components/HttpMethodSelect.spec.jsx | 23 - .../components/HttpMethodSelect.spec.tsx | 18 + .../components/IncrementByInput.spec.jsx | 22 - .../components/IncrementByInput.spec.tsx | 17 + .../components/IsLastCheckbox.spec.jsx | 22 - .../components/IsLastCheckbox.spec.tsx | 17 + .../components/MetricInput.spec.jsx | 39 - .../components/MetricInput.spec.tsx | 53 + .../components/NewMappingRule.spec.jsx | 24 - .../components/NewMappingRule.spec.tsx | 19 + .../components/PatternInput.spec.jsx | 24 - .../components/PatternInput.spec.tsx | 19 + .../components/PositionInput.spec.jsx | 22 - .../components/PositionInput.spec.tsx | 17 + .../components/RedirectUrlInput.spec.jsx | 22 - .../components/RedirectUrlInput.spec.tsx | 17 + .../components/BackendAPIIndexPage.spec.jsx | 21 - .../components/BackendAPIIndexPage.spec.tsx | 20 + ...{IndexPage.spec.jsx => IndexPage.spec.tsx} | 17 +- ...csTable.spec.jsx => MetricsTable.spec.tsx} | 31 +- .../components/ProductIndexPage.spec.jsx | 22 - .../components/ProductIndexPage.spec.tsx | 21 + .../Navigation/ActiveMenuTitle.spec.jsx | 36 - .../Navigation/ActiveMenuTitle.spec.tsx | 34 + ...ctor.spec.jsx => ContextSelector.spec.tsx} | 65 +- ...ticalNav.spec.jsx => VerticalNav.spec.tsx} | 11 +- .../ContextSelector.spec.tsx.snap | 189 + ...pec.jsx => ApplicationPlanSelect.spec.tsx} | 33 +- ...erSelect.spec.jsx => BuyerSelect.spec.tsx} | 11 +- ...m.spec.jsx => NewApplicationForm.spec.tsx} | 362 +- ...Select.spec.jsx => ProductSelect.spec.tsx} | 12 +- ...ct.spec.jsx => ServicePlanSelect.spec.tsx} | 40 +- .../NewService/NewServiceForm.spec.jsx | 81 - .../NewService/ServiceDiscoveryForm.spec.jsx | 67 - .../NewService/ServiceManualForm.spec.jsx | 37 - .../components/NewServiceForm.spec.tsx | 80 + .../components/ServiceDiscoveryForm.spec.tsx | 68 + .../components/ServiceManualForm.spec.tsx | 37 + .../ServiceSourceForm.spec.tsx} | 25 +- ...Message.spec.jsx => ErrorMessage.spec.tsx} | 13 +- .../formElements/FormWrapper.spec.jsx | 47 - .../formElements/FormWrapper.spec.tsx | 45 + ...x => HiddenServiceDiscoveryInput.spec.tsx} | 5 +- .../{Label.spec.jsx => Label.spec.tsx} | 13 +- .../{Select.spec.jsx => Select.spec.tsx} | 17 +- ...jsx => ServiceDiscoveryListItems.spec.tsx} | 43 +- ...ec.jsx => ServiceManualListItems.spec.tsx} | 9 +- .../ServiceManualListItems.spec.tsx.snap | 132 + ...er.spec.jsx => StripeFormWrapper.spec.tsx} | 21 +- ...eeForm.spec.jsx => BraintreeForm.spec.tsx} | 25 +- .../{Input.spec.jsx => Input.spec.tsx} | 22 +- .../{Label.spec.jsx => Label.spec.tsx} | 10 +- .../braintree/components/ListItem.spec.jsx | 28 - .../braintree/components/ListItem.spec.tsx | 33 + ...spec.jsx => ChangePlanSelectCard.spec.tsx} | 49 +- ...pec.jsx => DefaultPlanSelectCard.spec.tsx} | 32 +- ...lansTable.spec.jsx => PlansTable.spec.tsx} | 21 +- ...eCard.spec.jsx => PlansTableCard.spec.tsx} | 34 +- .../actions/OriginalPolicyChain.spec.ts | 22 + .../Policies/actions/PolicyChain.spec.jsx | 18 - .../Policies/actions/PolicyChain.spec.ts | 83 + .../Policies/actions/PolicyConfig.spec.ts | 22 + .../Policies/actions/PolicyRegistry.spec.jsx | 18 - .../Policies/actions/PolicyRegistry.spec.ts | 31 + .../Policies/actions/ThunkAction.spec.ts | 196 + .../Policies/actions/UISetting.spec.ts | 17 + ...rButton.spec.jsx => HeaderButton.spec.tsx} | 15 +- .../components/PoliciesWidget.spec.tsx | 30 + .../Policies/components/PolicyChain.spec.jsx | 90 - .../Policies/components/PolicyChain.spec.tsx | 93 + ...ec.jsx => PolicyChainHiddenInput.spec.tsx} | 10 +- ...yConfig.spec.jsx => PolicyConfig.spec.tsx} | 60 +- .../components/PolicyRegistry.spec.jsx | 80 - .../components/PolicyRegistry.spec.tsx | 78 + .../Policies/components/PolicyTile.spec.tsx | 24 + .../Policies/components/Root.spec.tsx | 1 + .../__snapshots__/HeaderButton.spec.tsx.snap | 59 + .../Policies/middleware/PolicyChain.spec.jsx | 120 - .../Policies/middleware/PolicyChain.spec.ts | 254 + .../reducers/OriginalPolicyChain.spec.ts | 18 + ...licyChain.spec.jsx => PolicyChain.spec.ts} | 6 +- ...cyConfig.spec.jsx => PolicyConfig.spec.ts} | 12 +- ...gistry.spec.jsx => PolicyRegistry.spec.ts} | 8 +- ...UISettings.spec.jsx => UISettings.spec.ts} | 2 - .../Policies/{util.spec.jsx => util.spec.ts} | 18 +- .../components/BackendsUsedListCard.spec.jsx | 61 - .../components/BackendsUsedListCard.spec.tsx | 57 + ...{IndexPage.spec.jsx => IndexPage.spec.tsx} | 20 +- ....spec.jsx => QuickStartContainer.spec.tsx} | 11 +- ...racker.spec.js => progressTracker.spec.ts} | 6 +- ....spec.js => replaceLinksExtension.spec.ts} | 2 - .../Settings/authentication-widget.spec.ts | 77 + ...> AuthenticationSettingsFieldset.spec.tsx} | 6 +- ...ction.spec.jsx => FormCollection.spec.tsx} | 13 +- .../components/Common/FormFieldset.spec.tsx | 23 + .../components/Common/FormLegend.spec.tsx | 19 + .../components/Common/RadioFieldset.spec.jsx | 20 - .../components/Common/RadioFieldset.spec.tsx | 29 + .../components/Common/SelectGroup.spec.jsx | 38 - .../components/Common/SelectGroup.spec.tsx | 49 + .../components/Common/TextInputGroup.spec.jsx | 27 - .../components/Common/TextInputGroup.spec.tsx | 32 + ...mCombo.spec.jsx => TypeItemCombo.spec.tsx} | 3 +- .../FormCollection.spec.tsx.snap | 31 + .../__snapshots__/RadioFieldset.spec.tsx.snap | 39 + .../__snapshots__/SelectGroup.spec.tsx.snap | 310 + .../TextInputGroup.spec.tsx.snap | 71 + .../__snapshots__/TypeItemCombo.spec.tsx.snap | 30 + .../{Form.spec.jsx => Form.spec.tsx} | 22 +- .../Settings/components/OidcFieldset.spec.jsx | 27 - .../Settings/components/OidcFieldset.spec.tsx | 24 + ...thenticationSettingsFieldset.spec.tsx.snap | 104 + .../__snapshots__/Form.spec.tsx.snap | 429 ++ .../__snapshots__/OidcFieldset.spec.tsx.snap | 114 + .../Stats/buyer/stats_application.spec.ts | 21 + .../Stats/inlinechart/inlineChart.spec.jsx | 109 - .../Stats/inlinechart/inlineChart.spec.tsx | 110 + .../Stats/lib/application_details.spec.ts | 34 + .../lib/application_metrics_source.spec.ts | 13 + .../applications_selector.spec.ts} | 18 +- .../applications_table.spec.ts} | 12 +- .../average_metrics_source.spec.ts} | 12 +- .../{chart.spec.js => lib/chart.spec.ts} | 0 .../chart_manager.spec.ts} | 28 +- .../csv_link.spec.ts} | 12 +- .../Stats/{menu.spec.js => lib/menu.spec.ts} | 60 +- .../methods_table.spec.ts} | 12 +- .../{metric.spec.js => lib/metric.spec.ts} | 4 +- .../metrics_list.spec.ts} | 14 +- .../metrics_selector.spec.ts} | 10 +- .../metrics_source.spec.ts} | 47 +- .../{series.spec.js => lib/series.spec.ts} | 20 +- .../{source.spec.js => lib/source.spec.ts} | 6 +- .../Stats/lib/source_collector.spec.ts | 87 + .../{state.spec.js => lib/state.spec.ts} | 48 +- .../Stats/lib/stats_helpers.spec.ts | 17 + .../{store.spec.js => lib/store.spec.ts} | 16 +- .../Stats/lib/top_apps_help_text.spec.ts | 38 + .../top_apps_source_collector.spec.ts} | 10 +- .../usage_chart.spec.ts} | 8 +- .../provider/stats_response_codes.spec.ts | 81 + .../stats_top_apps.spec.ts} | 4 +- .../Stats/source_collector.spec.js | 78 - spec/javascripts/Stats/stats_helpers.spec.js | 17 - .../Stats/stats_response_codes.spec.js | 84 - .../Stats/top_apps_help_text.spec.js | 37 - .../components/FeaturesFieldset.spec.jsx | 118 - .../components/FeaturesFieldset.spec.tsx | 114 + .../Users/components/PermissionsForm.spec.jsx | 220 - .../Users/components/PermissionsForm.spec.tsx | 217 + ...Group.spec.jsx => RoleRadioGroup.spec.tsx} | 39 +- .../components/ServicesFieldset.spec.jsx | 49 - .../components/ServicesFieldset.spec.tsx | 39 + .../utils/{utils.spec.jsx => utils.spec.ts} | 28 +- spec/javascripts/__mocks__/global-mocks.js | 6 +- .../__mocks__/react-sortable-hoc.js | 5 + .../__mocks__/utilities/CSRFToken.tsx | 9 + .../services/{index.spec.js => index.spec.ts} | 10 +- .../{migrate.spec.js => migrate.spec.ts} | 0 .../{setupTests.js => setupTests.ts} | 4 +- spec/javascripts/utilities/CSRFToken.spec.tsx | 47 + spec/javascripts/utilities/ajax.spec.ts | 94 + .../utilities/confirm-dialog.spec.ts | 13 + .../utilities/createReactWrapper.spec.tsx | 14 + spec/javascripts/utilities/fetchData.spec.ts | 24 + spec/javascripts/utilities/flash.spec.ts | 12 + ...sActiveTab.spec.js => isActiveTab.spec.ts} | 8 +- ...json-utils.spec.jsx => json-utils.spec.ts} | 9 +- .../utilities/paginateCollection.spec.ts | 45 + .../utilities/patternfly-utils.spec.tsx | 90 + spec/javascripts/utilities/toggle.spec.js | 66 - spec/javascripts/utilities/toggle.spec.ts | 63 + .../utilities/useClickOutside.spec.tsx | 38 + .../utilities/useSearchInputEffect.spec.tsx | 70 + spec/javascripts/utilities/utils.spec.jsx | 47 - tsconfig.json | 33 + tsconfig.prod.json | 6 + yarn.lock | 6111 ++++++++++------- 683 files changed, 20526 insertions(+), 17936 deletions(-) delete mode 100644 .flowconfig delete mode 100644 app/javascript/packs/ChangePassword.js delete mode 100644 app/javascript/packs/LoginPage.js delete mode 100644 app/javascript/packs/OAS3Autocomplete.js delete mode 100644 app/javascript/packs/RequestPasswordPage.js delete mode 100644 app/javascript/packs/SignUpPage.js delete mode 100644 app/javascript/packs/StripeForm.js delete mode 100644 app/javascript/packs/active_docs.js create mode 100644 app/javascript/packs/active_docs.ts rename app/javascript/packs/{add_backend_usage.js => add_backend_usage.ts} (66%) delete mode 100644 app/javascript/packs/api_selector.js create mode 100644 app/javascript/packs/api_selector.ts rename app/javascript/packs/{backend_api_metrics_index.js => backend_api_metrics_index.ts} (69%) rename app/javascript/packs/{backend_apis_index.js => backend_apis_index.ts} (53%) delete mode 100644 app/javascript/packs/backends_used_list.js create mode 100644 app/javascript/packs/backends_used_list.ts delete mode 100644 app/javascript/packs/braintree_customer_form.js create mode 100644 app/javascript/packs/braintree_customer_form.ts create mode 100644 app/javascript/packs/change_password.ts rename app/javascript/packs/{change_plan_select.js => change_plan_select.ts} (53%) rename app/javascript/packs/{dashboard.js => dashboard.ts} (100%) rename app/javascript/packs/{dashboard_backends_widget.js => dashboard_backends_widget.ts} (50%) delete mode 100644 app/javascript/packs/dashboard_products_widget.js create mode 100644 app/javascript/packs/dashboard_products_widget.ts rename app/javascript/packs/{default_plan_selector.js => default_plan_selector.ts} (50%) rename app/javascript/packs/email_configurations/{edit.js => edit.ts} (88%) rename app/javascript/packs/email_configurations/{index.js => index.ts} (76%) rename app/javascript/packs/email_configurations/{new.js => new.ts} (88%) delete mode 100644 app/javascript/packs/inlineChart.js create mode 100644 app/javascript/packs/inline_chart.tsx delete mode 100644 app/javascript/packs/invoice_payment.js create mode 100644 app/javascript/packs/invoice_payment.ts rename app/javascript/packs/{load_stripe.js => load_stripe.ts} (50%) create mode 100644 app/javascript/packs/login_page.ts delete mode 100644 app/javascript/packs/navigation.js create mode 100644 app/javascript/packs/navigation.ts rename app/javascript/packs/{new_application.js => new_application.ts} (75%) delete mode 100644 app/javascript/packs/new_mapping_rule.js create mode 100644 app/javascript/packs/new_mapping_rule.ts delete mode 100644 app/javascript/packs/new_service.js create mode 100644 app/javascript/packs/new_service.ts delete mode 100644 app/javascript/packs/permissions.js create mode 100644 app/javascript/packs/permissions.ts rename app/javascript/packs/{plans-metrics.js => plans_metrics.ts} (64%) delete mode 100644 app/javascript/packs/plans_table.js create mode 100644 app/javascript/packs/plans_table.ts rename app/javascript/packs/{policies.js => policies.ts} (73%) rename app/javascript/packs/{product_metrics_index.js => product_metrics_index.ts} (68%) delete mode 100644 app/javascript/packs/products_index.js create mode 100644 app/javascript/packs/products_index.ts delete mode 100644 app/javascript/packs/products_used_list.js create mode 100644 app/javascript/packs/products_used_list.ts rename app/javascript/packs/{providerStats.js => provider_stats.ts} (99%) rename app/javascript/packs/quickstarts/{container.js => container.ts} (74%) create mode 100644 app/javascript/packs/request_password_page.ts delete mode 100644 app/javascript/packs/service_active_docs.js create mode 100644 app/javascript/packs/service_active_docs.ts rename app/javascript/packs/{services.js => services.ts} (100%) rename app/javascript/packs/{settings.js => settings.ts} (100%) delete mode 100644 app/javascript/packs/settingsPageStyles.js create mode 100644 app/javascript/packs/settings_page_styles.ts create mode 100644 app/javascript/packs/sign_up_page.ts rename app/javascript/packs/{stats.js => stats.ts} (99%) create mode 100644 app/javascript/packs/stripe_form.ts rename app/javascript/packs/{system_name_input_popover.js => system_name_input_popover.ts} (61%) rename app/javascript/packs/{validateSignup.js => validate_signup.ts} (62%) delete mode 100644 app/javascript/packs/vertical_nav.js create mode 100644 app/javascript/packs/vertical_nav.ts rename app/javascript/packs/{wizard_backend_api.js => wizard_backend_api.ts} (52%) create mode 100644 app/javascript/src/ActiveDocs/OAS3Autocomplete.ts rename app/javascript/src/BackendApis/components/{AddBackendForm.jsx => AddBackendForm.tsx} (50%) rename app/javascript/src/BackendApis/components/{BackendSelect.jsx => BackendSelect.tsx} (62%) delete mode 100644 app/javascript/src/BackendApis/components/DescriptionInput.jsx create mode 100644 app/javascript/src/BackendApis/components/DescriptionInput.tsx delete mode 100644 app/javascript/src/BackendApis/components/IndexPage.jsx create mode 100644 app/javascript/src/BackendApis/components/IndexPage.tsx rename app/javascript/src/BackendApis/components/{NameInput.jsx => NameInput.tsx} (54%) rename app/javascript/src/BackendApis/components/{NewBackendForm.jsx => NewBackendForm.tsx} (61%) delete mode 100644 app/javascript/src/BackendApis/components/NewBackendModal.jsx create mode 100644 app/javascript/src/BackendApis/components/NewBackendModal.tsx rename app/javascript/src/BackendApis/components/{PathInput.jsx => PathInput.tsx} (64%) rename app/javascript/src/BackendApis/components/{PrivateEndpointInput.jsx => PrivateEndpointInput.tsx} (64%) rename app/javascript/src/BackendApis/components/{ProductsUsedListCard.jsx => ProductsUsedListCard.tsx} (52%) rename app/javascript/src/BackendApis/components/{SystemNameInput.jsx => SystemNameInput.tsx} (63%) delete mode 100644 app/javascript/src/BackendApis/index.js delete mode 100644 app/javascript/src/BackendApis/types.js create mode 100644 app/javascript/src/BackendApis/types.ts delete mode 100644 app/javascript/src/ChangePassword/components/ChangePassword.jsx create mode 100644 app/javascript/src/ChangePassword/components/ChangePassword.tsx rename app/javascript/src/ChangePassword/components/{ChangePasswordHooks.jsx => ChangePasswordHooks.ts} (51%) delete mode 100644 app/javascript/src/ChangePassword/index.jsx rename app/javascript/src/Common/components/{CompactListCard.jsx => CompactListCard.tsx} (56%) delete mode 100644 app/javascript/src/Common/components/FancySelect.jsx create mode 100644 app/javascript/src/Common/components/FancySelect.tsx delete mode 100644 app/javascript/src/Common/components/HelperText.jsx create mode 100644 app/javascript/src/Common/components/HelperText.tsx delete mode 100644 app/javascript/src/Common/components/MicroPagination.jsx create mode 100644 app/javascript/src/Common/components/MicroPagination.tsx rename app/javascript/src/Common/components/{NoMatchFound.jsx => NoMatchFound.tsx} (50%) create mode 100644 app/javascript/src/Common/components/Pagination.tsx delete mode 100644 app/javascript/src/Common/components/Select.jsx create mode 100644 app/javascript/src/Common/components/Select.tsx rename app/javascript/src/Common/components/{SelectWithModal.jsx => SelectWithModal.tsx} (64%) delete mode 100644 app/javascript/src/Common/components/Spinner.jsx create mode 100644 app/javascript/src/Common/components/Spinner.tsx delete mode 100644 app/javascript/src/Common/components/SystemNamePopover.jsx create mode 100644 app/javascript/src/Common/components/SystemNamePopover.tsx rename app/javascript/src/Common/components/{TableModal.jsx => TableModal.tsx} (68%) rename app/javascript/src/Common/components/{ToolbarSearch.jsx => ToolbarSearch.tsx} (50%) rename app/javascript/src/Common/components/{UserDefinedField.jsx => UserDefinedField.tsx} (66%) delete mode 100644 app/javascript/src/Common/index.js rename app/javascript/src/Dashboard/{ajax-widget.jsx => ajax-widget.ts} (57%) delete mode 100644 app/javascript/src/Dashboard/chart.jsx create mode 100644 app/javascript/src/Dashboard/chart.ts rename app/javascript/src/Dashboard/components/{APIDataListItem.jsx => APIDataListItem.tsx} (57%) rename app/javascript/src/Dashboard/components/{BackendsWidget.jsx => BackendsWidget.tsx} (53%) rename app/javascript/src/Dashboard/components/{ProductsWidget.jsx => ProductsWidget.tsx} (54%) rename app/javascript/src/Dashboard/{index.jsx => index.ts} (71%) delete mode 100644 app/javascript/src/EmailConfigurations/components/EditPage.jsx create mode 100644 app/javascript/src/EmailConfigurations/components/EditPage.tsx delete mode 100644 app/javascript/src/EmailConfigurations/components/EmailConfigurationForm.jsx create mode 100644 app/javascript/src/EmailConfigurations/components/EmailConfigurationForm.tsx delete mode 100644 app/javascript/src/EmailConfigurations/components/EmailConfigurationsTable.jsx create mode 100644 app/javascript/src/EmailConfigurations/components/EmailConfigurationsTable.tsx rename app/javascript/src/EmailConfigurations/components/{IndexPage.jsx => IndexPage.tsx} (62%) delete mode 100644 app/javascript/src/EmailConfigurations/components/NewPage.jsx create mode 100644 app/javascript/src/EmailConfigurations/components/NewPage.tsx rename app/javascript/src/EmailConfigurations/components/form-fields/{EmailInput.jsx => EmailInput.tsx} (62%) rename app/javascript/src/EmailConfigurations/components/form-fields/{PasswordInput.jsx => PasswordInput.tsx} (63%) rename app/javascript/src/EmailConfigurations/components/form-fields/{PasswordRepeatInput.jsx => PasswordRepeatInput.tsx} (59%) rename app/javascript/src/EmailConfigurations/components/form-fields/{UserNameInput.jsx => UserNameInput.tsx} (61%) delete mode 100644 app/javascript/src/EmailConfigurations/components/form-fields/index.js delete mode 100644 app/javascript/src/EmailConfigurations/types.js create mode 100644 app/javascript/src/EmailConfigurations/types.ts delete mode 100644 app/javascript/src/Logic/BuyerLogic.js create mode 100644 app/javascript/src/Logic/BuyerLogic.ts delete mode 100644 app/javascript/src/Logic/index.js delete mode 100644 app/javascript/src/LoginPage/LoginPageWrapper.jsx create mode 100644 app/javascript/src/LoginPage/LoginPageWrapper.tsx delete mode 100644 app/javascript/src/LoginPage/RequestPasswordWrapper.jsx create mode 100644 app/javascript/src/LoginPage/RequestPasswordWrapper.tsx delete mode 100644 app/javascript/src/LoginPage/SignupPageWrapper.jsx create mode 100644 app/javascript/src/LoginPage/SignupPageWrapper.tsx delete mode 100644 app/javascript/src/LoginPage/index.js delete mode 100644 app/javascript/src/LoginPage/loginForms/AuthenticationProviders.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/AuthenticationProviders.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/FlashMessages.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/FlashMessages.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/ForgotCredentials.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/ForgotCredentials.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/FormGroups.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/FormGroups.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/HiddenInputs.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/HiddenInputs.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/Login3scaleForm.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/Login3scaleForm.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/RequestPasswordForm.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/RequestPasswordForm.tsx delete mode 100644 app/javascript/src/LoginPage/loginForms/SignupForm.jsx create mode 100644 app/javascript/src/LoginPage/loginForms/SignupForm.tsx delete mode 100644 app/javascript/src/LoginPage/utils/formValidation.js create mode 100644 app/javascript/src/LoginPage/utils/formValidation.ts delete mode 100644 app/javascript/src/MappingRules/components/HttpMethodSelect.jsx create mode 100644 app/javascript/src/MappingRules/components/HttpMethodSelect.tsx rename app/javascript/src/MappingRules/components/{IncrementByInput.jsx => IncrementByInput.tsx} (53%) delete mode 100644 app/javascript/src/MappingRules/components/IsLastCheckbox.jsx create mode 100644 app/javascript/src/MappingRules/components/IsLastCheckbox.tsx rename app/javascript/src/MappingRules/components/{MetricInput.jsx => MetricInput.tsx} (56%) delete mode 100644 app/javascript/src/MappingRules/components/NewMappingRule.jsx create mode 100644 app/javascript/src/MappingRules/components/NewMappingRule.tsx delete mode 100644 app/javascript/src/MappingRules/components/PatternInput.jsx create mode 100644 app/javascript/src/MappingRules/components/PatternInput.tsx delete mode 100644 app/javascript/src/MappingRules/components/PositionInput.jsx create mode 100644 app/javascript/src/MappingRules/components/PositionInput.tsx rename app/javascript/src/MappingRules/components/{RedirectUrlInput.jsx => RedirectUrlInput.tsx} (51%) delete mode 100644 app/javascript/src/MappingRules/index.js delete mode 100644 app/javascript/src/Metrics/components/BackendAPIIndexPage.jsx create mode 100644 app/javascript/src/Metrics/components/BackendAPIIndexPage.tsx rename app/javascript/src/Metrics/components/{IndexPage.jsx => IndexPage.tsx} (58%) delete mode 100644 app/javascript/src/Metrics/components/MetricsTable.jsx create mode 100644 app/javascript/src/Metrics/components/MetricsTable.tsx delete mode 100644 app/javascript/src/Metrics/components/ProductIndexPage.jsx create mode 100644 app/javascript/src/Metrics/components/ProductIndexPage.tsx delete mode 100644 app/javascript/src/Metrics/index.js rename app/javascript/src/Metrics/types/{index.js => index.ts} (81%) rename app/javascript/src/Navigation/{styles => components}/ActiveMenuTitle.scss (100%) rename app/javascript/src/Navigation/components/{ActiveMenuTitle.jsx => ActiveMenuTitle.tsx} (71%) rename app/javascript/src/Navigation/{styles => components}/ContextSelector.scss (100%) rename app/javascript/src/Navigation/components/{ContextSelector.jsx => ContextSelector.tsx} (52%) delete mode 100644 app/javascript/src/Navigation/components/VerticalNav.jsx rename app/javascript/src/Navigation/{styles => components}/VerticalNav.scss (100%) create mode 100644 app/javascript/src/Navigation/components/VerticalNav.tsx rename app/javascript/src/Navigation/utils/{toggle_navigation.jsx => toggle_navigation.ts} (59%) delete mode 100644 app/javascript/src/NewApplication/components/ApplicationPlanSelect.jsx create mode 100644 app/javascript/src/NewApplication/components/ApplicationPlanSelect.tsx rename app/javascript/src/NewApplication/components/{BuyerSelect.jsx => BuyerSelect.tsx} (62%) rename app/javascript/src/NewApplication/components/{NewApplicationForm.jsx => NewApplicationForm.tsx} (56%) rename app/javascript/src/NewApplication/components/{ProductSelect.jsx => ProductSelect.tsx} (62%) rename app/javascript/src/NewApplication/components/{ServicePlanSelect.jsx => ServicePlanSelect.tsx} (55%) rename app/javascript/src/NewApplication/data/{Buyers.js => Buyers.ts} (97%) rename app/javascript/src/NewApplication/data/{Products.js => Products.ts} (97%) delete mode 100644 app/javascript/src/NewApplication/data/index.js delete mode 100644 app/javascript/src/NewApplication/index.js delete mode 100644 app/javascript/src/NewApplication/types.js create mode 100644 app/javascript/src/NewApplication/types.ts delete mode 100644 app/javascript/src/NewService/components/FormElements/ErrorMessage.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/ErrorMessage.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/FormWrapper.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/FormWrapper.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/HiddenServiceDiscoveryInput.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/HiddenServiceDiscoveryInput.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/Label.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/Label.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/Select.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/Select.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/ServiceDiscoveryListItems.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/ServiceDiscoveryListItems.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/ServiceManualListItems.jsx create mode 100644 app/javascript/src/NewService/components/FormElements/ServiceManualListItems.tsx delete mode 100644 app/javascript/src/NewService/components/FormElements/index.jsx delete mode 100644 app/javascript/src/NewService/components/NewServiceForm.jsx create mode 100644 app/javascript/src/NewService/components/NewServiceForm.tsx delete mode 100644 app/javascript/src/NewService/components/ServiceDiscoveryForm.jsx create mode 100644 app/javascript/src/NewService/components/ServiceDiscoveryForm.tsx delete mode 100644 app/javascript/src/NewService/components/ServiceManualForm.jsx create mode 100644 app/javascript/src/NewService/components/ServiceManualForm.tsx rename app/javascript/src/NewService/components/{ServiceSourceForm.jsx => ServiceSourceForm.tsx} (72%) delete mode 100644 app/javascript/src/NewService/index.jsx delete mode 100644 app/javascript/src/NewService/types/index.js create mode 100644 app/javascript/src/NewService/types/index.ts rename app/javascript/src/PaymentGateways/braintree/{BraintreeBillingAddressFields.jsx => BraintreeBillingAddressFields.tsx} (72%) delete mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeCardFields.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeCardFields.tsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeForm.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeForm.tsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeFormWrapper.jsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeSubmitFields.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/BraintreeSubmitFields.tsx rename app/javascript/src/PaymentGateways/braintree/{BraintreeUserFields.jsx => BraintreeUserFields.tsx} (68%) rename app/javascript/src/PaymentGateways/braintree/{braintree.js => braintree.ts} (55%) delete mode 100644 app/javascript/src/PaymentGateways/braintree/components/Input.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/components/Input.tsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/components/Label.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/components/Label.tsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/components/ListItem.jsx create mode 100644 app/javascript/src/PaymentGateways/braintree/components/ListItem.tsx delete mode 100644 app/javascript/src/PaymentGateways/braintree/types.js create mode 100644 app/javascript/src/PaymentGateways/braintree/types.ts delete mode 100644 app/javascript/src/PaymentGateways/index.js rename app/javascript/src/PaymentGateways/stripe/components/{StripeCardForm.jsx => StripeCardForm.tsx} (53%) delete mode 100644 app/javascript/src/PaymentGateways/stripe/components/StripeFormWrapper.jsx rename app/javascript/src/PaymentGateways/stripe/{styles/stripe.scss => components/StripeFormWrapper.scss} (100%) create mode 100644 app/javascript/src/PaymentGateways/stripe/components/StripeFormWrapper.tsx rename app/javascript/src/Plans/components/{ChangePlanSelectCard.jsx => ChangePlanSelectCard.tsx} (59%) rename app/javascript/src/Plans/components/{DefaultPlanSelectCard.jsx => DefaultPlanSelectCard.tsx} (59%) delete mode 100644 app/javascript/src/Plans/components/PlansTable.jsx create mode 100644 app/javascript/src/Plans/components/PlansTable.tsx delete mode 100644 app/javascript/src/Plans/components/PlansTableCard.jsx create mode 100644 app/javascript/src/Plans/components/PlansTableCard.tsx delete mode 100644 app/javascript/src/Plans/index.js delete mode 100644 app/javascript/src/Policies/actions/OriginalPolicyChain.jsx create mode 100644 app/javascript/src/Policies/actions/OriginalPolicyChain.ts delete mode 100644 app/javascript/src/Policies/actions/PolicyChain.jsx create mode 100644 app/javascript/src/Policies/actions/PolicyChain.ts rename app/javascript/src/Policies/actions/{PolicyConfig.jsx => PolicyConfig.ts} (58%) delete mode 100644 app/javascript/src/Policies/actions/PolicyRegistry.jsx create mode 100644 app/javascript/src/Policies/actions/PolicyRegistry.ts delete mode 100644 app/javascript/src/Policies/actions/ThunkActions.jsx create mode 100644 app/javascript/src/Policies/actions/ThunkActions.ts delete mode 100644 app/javascript/src/Policies/actions/UISettings.jsx create mode 100644 app/javascript/src/Policies/actions/UISettings.ts rename app/javascript/src/Policies/actions/{index.jsx => index.ts} (96%) delete mode 100644 app/javascript/src/Policies/components/HeaderButton.jsx create mode 100644 app/javascript/src/Policies/components/HeaderButton.tsx rename app/javascript/src/Policies/components/{PoliciesWidget.jsx => PoliciesWidget.tsx} (68%) delete mode 100644 app/javascript/src/Policies/components/PolicyChain.jsx create mode 100644 app/javascript/src/Policies/components/PolicyChain.tsx rename app/javascript/src/Policies/components/{PolicyChainHiddenInput.jsx => PolicyChainHiddenInput.tsx} (56%) rename app/javascript/src/Policies/components/{PolicyConfig.jsx => PolicyConfig.tsx} (70%) rename app/javascript/src/Policies/components/{PolicyRegistry.jsx => PolicyRegistry.tsx} (50%) delete mode 100644 app/javascript/src/Policies/components/PolicyTile.jsx create mode 100644 app/javascript/src/Policies/components/PolicyTile.tsx delete mode 100644 app/javascript/src/Policies/components/Root.jsx create mode 100644 app/javascript/src/Policies/components/Root.tsx delete mode 100644 app/javascript/src/Policies/index.jsx create mode 100644 app/javascript/src/Policies/index.tsx delete mode 100644 app/javascript/src/Policies/middleware/PolicyChain.jsx create mode 100644 app/javascript/src/Policies/middleware/PolicyChain.ts delete mode 100644 app/javascript/src/Policies/reducers/OriginalPolicyChain.jsx create mode 100644 app/javascript/src/Policies/reducers/OriginalPolicyChain.ts rename app/javascript/src/Policies/reducers/{PolicyChain.jsx => PolicyChain.ts} (61%) rename app/javascript/src/Policies/reducers/{PolicyConfig.jsx => PolicyConfig.ts} (79%) delete mode 100644 app/javascript/src/Policies/reducers/PolicyRegistry.jsx create mode 100644 app/javascript/src/Policies/reducers/PolicyRegistry.ts rename app/javascript/src/Policies/reducers/{UISettings.jsx => UISettings.ts} (86%) rename app/javascript/src/Policies/reducers/{index.jsx => index.ts} (86%) rename app/javascript/src/Policies/reducers/{initialState.jsx => initialState.ts} (92%) rename app/javascript/src/Policies/store/{configureStore.jsx => configureStore.ts} (81%) delete mode 100644 app/javascript/src/Policies/store/index.jsx delete mode 100644 app/javascript/src/Policies/types/Actions.jsx create mode 100644 app/javascript/src/Policies/types/Actions.ts delete mode 100644 app/javascript/src/Policies/types/Policies.jsx create mode 100644 app/javascript/src/Policies/types/Policies.ts delete mode 100644 app/javascript/src/Policies/types/State.jsx create mode 100644 app/javascript/src/Policies/types/State.ts delete mode 100644 app/javascript/src/Policies/types/index.jsx create mode 100644 app/javascript/src/Policies/types/index.ts rename app/javascript/src/Policies/{util.jsx => util.ts} (63%) rename app/javascript/src/Policies/{webpack-public-path.js => webpack-public-path.ts} (99%) rename app/javascript/src/Products/components/{BackendsUsedListCard.jsx => BackendsUsedListCard.tsx} (52%) delete mode 100644 app/javascript/src/Products/components/IndexPage.jsx create mode 100644 app/javascript/src/Products/components/IndexPage.tsx delete mode 100644 app/javascript/src/Products/index.js delete mode 100644 app/javascript/src/Products/types.js create mode 100644 app/javascript/src/Products/types.ts rename app/javascript/src/QuickStarts/components/{QuickStartContainer.jsx => QuickStartContainer.tsx} (74%) rename app/javascript/src/QuickStarts/templates/{index.js => index.ts} (98%) delete mode 100644 app/javascript/src/QuickStarts/utils/progressTracker.js create mode 100644 app/javascript/src/QuickStarts/utils/progressTracker.ts rename app/javascript/src/QuickStarts/utils/{replaceLinksExtension.js => replaceLinksExtension.ts} (68%) delete mode 100644 app/javascript/src/Settings/authentication-widget.jsx create mode 100644 app/javascript/src/Settings/authentication-widget.ts delete mode 100644 app/javascript/src/Settings/components/AuthenticationSettingsFieldset.jsx create mode 100644 app/javascript/src/Settings/components/AuthenticationSettingsFieldset.tsx delete mode 100644 app/javascript/src/Settings/components/Common/FormCollection.jsx create mode 100644 app/javascript/src/Settings/components/Common/FormCollection.tsx delete mode 100644 app/javascript/src/Settings/components/Common/FormFieldset.jsx create mode 100644 app/javascript/src/Settings/components/Common/FormFieldset.tsx delete mode 100644 app/javascript/src/Settings/components/Common/FormLegend.jsx create mode 100644 app/javascript/src/Settings/components/Common/FormLegend.tsx rename app/javascript/src/Settings/components/Common/{RadioFieldset.jsx => RadioFieldset.tsx} (50%) delete mode 100644 app/javascript/src/Settings/components/Common/SelectGroup.jsx create mode 100644 app/javascript/src/Settings/components/Common/SelectGroup.tsx rename app/javascript/src/Settings/components/Common/{TextInputGroup.jsx => TextInputGroup.tsx} (56%) delete mode 100644 app/javascript/src/Settings/components/Common/TypeItemCombo.jsx create mode 100644 app/javascript/src/Settings/components/Common/TypeItemCombo.tsx delete mode 100644 app/javascript/src/Settings/components/Common/index.jsx delete mode 100644 app/javascript/src/Settings/components/Form.jsx create mode 100644 app/javascript/src/Settings/components/Form.tsx delete mode 100644 app/javascript/src/Settings/components/OidcFieldset.jsx create mode 100644 app/javascript/src/Settings/components/OidcFieldset.tsx rename app/javascript/src/Settings/{defaults.jsx => defaults.ts} (85%) delete mode 100644 app/javascript/src/Settings/index.jsx delete mode 100644 app/javascript/src/Settings/types/index.jsx create mode 100644 app/javascript/src/Settings/types/index.ts rename app/javascript/src/Stats/inlinechart/{index.jsx => index.tsx} (77%) create mode 100644 app/javascript/src/Stats/stats.d.ts delete mode 100644 app/javascript/src/Types/Api.jsx create mode 100644 app/javascript/src/Types/Api.ts delete mode 100644 app/javascript/src/Types/FlashMessages.jsx create mode 100644 app/javascript/src/Types/FlashMessages.ts delete mode 100644 app/javascript/src/Types/NavigationTypes.jsx create mode 100644 app/javascript/src/Types/NavigationTypes.ts delete mode 100644 app/javascript/src/Types/Signup.jsx create mode 100644 app/javascript/src/Types/Signup.ts delete mode 100644 app/javascript/src/Types/SwaggerTypes.jsx create mode 100644 app/javascript/src/Types/SwaggerTypes.ts create mode 100644 app/javascript/src/Types/custom.d.ts create mode 100644 app/javascript/src/Types/globals.d.ts delete mode 100644 app/javascript/src/Types/index.js create mode 100644 app/javascript/src/Types/index.ts delete mode 100644 app/javascript/src/Types/libs/libdefs.js rename app/javascript/src/Users/components/{FeaturesFieldset.jsx => FeaturesFieldset.tsx} (54%) rename app/javascript/src/Users/components/{PermissionsForm.jsx => PermissionsForm.tsx} (59%) delete mode 100644 app/javascript/src/Users/components/RoleRadioGroup.jsx create mode 100644 app/javascript/src/Users/components/RoleRadioGroup.tsx rename app/javascript/src/Users/components/{ServicesFieldset.jsx => ServicesFieldset.tsx} (61%) delete mode 100644 app/javascript/src/Users/types/index.jsx create mode 100644 app/javascript/src/Users/types/index.ts rename app/javascript/src/Users/utils/{index.jsx => index.ts} (72%) delete mode 100644 app/javascript/src/services/index.jsx create mode 100644 app/javascript/src/services/index.ts delete mode 100644 app/javascript/src/services/migrate.jsx create mode 100644 app/javascript/src/services/migrate.ts delete mode 100644 app/javascript/src/utilities/CSRFToken.jsx create mode 100644 app/javascript/src/utilities/CSRFToken.tsx rename app/javascript/src/utilities/{ajax.js => ajax.ts} (55%) delete mode 100644 app/javascript/src/utilities/alert.js delete mode 100644 app/javascript/src/utilities/confirm-dialog.jsx create mode 100644 app/javascript/src/utilities/confirm-dialog.ts rename app/javascript/src/utilities/{createReactWrapper.jsx => createReactWrapper.ts} (55%) rename app/javascript/src/utilities/{fetchData.js => fetchData.ts} (81%) create mode 100644 app/javascript/src/utilities/flash.ts delete mode 100644 app/javascript/src/utilities/index.js rename app/javascript/src/utilities/{isActiveTab.js => isActiveTab.ts} (72%) rename app/javascript/src/utilities/{json-utils.jsx => json-utils.ts} (54%) delete mode 100644 app/javascript/src/utilities/paginateCollection.js create mode 100644 app/javascript/src/utilities/paginateCollection.ts delete mode 100644 app/javascript/src/utilities/patternfly-utils.jsx create mode 100644 app/javascript/src/utilities/patternfly-utils.tsx delete mode 100644 app/javascript/src/utilities/test-utils.js create mode 100644 app/javascript/src/utilities/test-utils.ts delete mode 100644 app/javascript/src/utilities/toggle.jsx create mode 100644 app/javascript/src/utilities/toggle.ts rename app/javascript/src/utilities/{useClickOutside.js => useClickOutside.ts} (54%) delete mode 100644 app/javascript/src/utilities/useSearchInputEffect.js create mode 100644 app/javascript/src/utilities/useSearchInputEffect.ts create mode 100644 eslint-naming-conventions.json delete mode 100644 lib/generators/react_page/USAGE delete mode 100644 lib/generators/react_page/react_page_generator.rb create mode 100644 spec/javascripts/.eslintrc rename spec/javascripts/ActiveDocs/{OAS3Autocomplete.spec.jsx => OAS3Autocomplete.spec.ts} (80%) delete mode 100644 spec/javascripts/BackendApis/components/AddBackendForm.spec.jsx create mode 100644 spec/javascripts/BackendApis/components/AddBackendForm.spec.tsx rename spec/javascripts/BackendApis/components/{BackendSelect.spec.jsx => BackendSelect.spec.tsx} (76%) rename spec/javascripts/BackendApis/components/{DescriptionInput.spec.jsx => DescriptionInput.spec.tsx} (50%) rename spec/javascripts/BackendApis/components/{IndexPage.spec.jsx => IndexPage.spec.tsx} (78%) delete mode 100644 spec/javascripts/BackendApis/components/NameInput.spec.jsx create mode 100644 spec/javascripts/BackendApis/components/NameInput.spec.tsx delete mode 100644 spec/javascripts/BackendApis/components/NewBackendForm.spec.jsx create mode 100644 spec/javascripts/BackendApis/components/NewBackendForm.spec.tsx rename spec/javascripts/BackendApis/components/{NewBackendModal.spec.jsx => NewBackendModal.spec.tsx} (53%) rename spec/javascripts/BackendApis/components/{PathInput.spec.jsx => PathInput.spec.tsx} (51%) delete mode 100644 spec/javascripts/BackendApis/components/PrivateEndpointInput.spec.jsx create mode 100644 spec/javascripts/BackendApis/components/PrivateEndpointInput.spec.tsx delete mode 100644 spec/javascripts/BackendApis/components/ProductsUsedList.spec.jsx create mode 100644 spec/javascripts/BackendApis/components/ProductsUsedList.spec.tsx rename spec/javascripts/BackendApis/components/{SystemNameInput.spec.jsx => SystemNameInput.spec.tsx} (50%) rename spec/javascripts/ChangePassword/{ChangePassword.spec.jsx => ChangePassword.spec.tsx} (73%) create mode 100644 spec/javascripts/ChangePassword/__snapshots__/ChangePassword.spec.tsx.snap rename spec/javascripts/Common/components/{CompactListCard.spec.jsx => CompactListCard.spec.tsx} (63%) rename spec/javascripts/Common/components/{FancySelect.spec.jsx => FancySelect.spec.tsx} (68%) rename spec/javascripts/Common/components/{FormFieldset.spec.jsx => FormFieldset.spec.tsx} (88%) rename spec/javascripts/Common/components/{FormLegend.spec.jsx => FormLegend.spec.tsx} (62%) create mode 100644 spec/javascripts/Common/components/HelperText.spec.tsx rename spec/javascripts/Common/components/{MicroPagination.spec.jsx => MicroPagination.spec.tsx} (56%) delete mode 100644 spec/javascripts/Common/components/NoMatchFound.spec.jsx create mode 100644 spec/javascripts/Common/components/NoMatchFound.spec.tsx rename spec/javascripts/Common/components/{Select.spec.jsx => Select.spec.tsx} (76%) rename spec/javascripts/Common/components/{SelectWithModal.spec.jsx => SelectWithModal.spec.tsx} (68%) create mode 100644 spec/javascripts/Common/components/Spinner.spec.tsx create mode 100644 spec/javascripts/Common/components/SystemNamePopover.spec.tsx rename spec/javascripts/Common/components/{TableModal.spec.jsx => TableModal.spec.tsx} (86%) delete mode 100644 spec/javascripts/Common/components/ToolbarSearch.spec.jsx create mode 100644 spec/javascripts/Common/components/ToolbarSearch.spec.tsx rename spec/javascripts/Common/components/{UserDefinedSelect.spec.jsx => UserDefinedField.spec.tsx} (57%) rename spec/javascripts/Common/components/__snapshots__/{FormFieldset.spec.jsx.snap => FormFieldset.spec.tsx.snap} (100%) rename spec/javascripts/Common/components/__snapshots__/{FormLegend.spec.jsx.snap => FormLegend.spec.tsx.snap} (100%) delete mode 100644 spec/javascripts/Common/components/__snapshots__/SuperSelect.spec.jsx.snap rename spec/javascripts/Dashboard/{chart.spec.js => chart.spec.tsx} (100%) create mode 100644 spec/javascripts/Dashboard/components/APIDataListItem.spec.tsx create mode 100644 spec/javascripts/Dashboard/components/BackendsWidget.spec.tsx create mode 100644 spec/javascripts/Dashboard/components/ProductsWidget.spec.tsx rename spec/javascripts/EmailConfigurations/components/{EditPage.spec.jsx => EditPage.spec.tsx} (60%) rename spec/javascripts/EmailConfigurations/components/{EmailConfigurationForm.spec.jsx => EmailConfigurationForm.spec.tsx} (82%) rename spec/javascripts/EmailConfigurations/components/{EmailConfigurationsTable.spec.jsx => EmailConfigurationsTable.spec.tsx} (58%) rename spec/javascripts/EmailConfigurations/components/{IndexPage.spec.jsx => IndexPage.spec.tsx} (72%) rename spec/javascripts/EmailConfigurations/components/{NewPage.spec.jsx => NewPage.spec.tsx} (58%) rename spec/javascripts/EmailConfigurations/components/form-fields/{EmailInput.spec.jsx => EmailInput.spec.tsx} (74%) rename spec/javascripts/EmailConfigurations/components/form-fields/{PasswordInput.spec.jsx => PasswordInput.spec.tsx} (74%) rename spec/javascripts/EmailConfigurations/components/form-fields/{PasswordRepeatInput.spec.jsx => PasswordRepeatInput.spec.tsx} (75%) rename spec/javascripts/EmailConfigurations/components/form-fields/{UserNameInput.spec.jsx => UserNameInput.spec.tsx} (74%) rename spec/javascripts/Logic/{BuyerLogic.spec.jsx => BuyerLogic.spec.tsx} (77%) delete mode 100644 spec/javascripts/LoginPage/ForgotCredentials.spec.jsx rename spec/javascripts/LoginPage/{LoginPageWrapper.spec.jsx => LoginPageWrapper.spec.tsx} (71%) rename spec/javascripts/LoginPage/{SignupPageWrapper.spec.jsx => SignupPageWrapper.spec.tsx} (66%) rename spec/javascripts/LoginPage/__snapshots__/{ForgotCredentials.spec.jsx.snap => ForgotCredentials.spec.tsx.snap} (100%) rename spec/javascripts/LoginPage/__snapshots__/{LoginPageWrapper.spec.jsx.snap => LoginPageWrapper.spec.tsx.snap} (93%) delete mode 100644 spec/javascripts/LoginPage/__snapshots__/RequestPasswordForm.spec.jsx.snap create mode 100644 spec/javascripts/LoginPage/__snapshots__/RequestPasswordForm.spec.tsx.snap rename spec/javascripts/LoginPage/{AuthenticationProviders.spec.jsx => loginForms/AuthenticationProviders.spec.tsx} (59%) rename spec/javascripts/LoginPage/{FlashMessages.spec.jsx => loginForms/FlashMessages.spec.tsx} (59%) create mode 100644 spec/javascripts/LoginPage/loginForms/ForgotCredentials.spec.tsx rename spec/javascripts/LoginPage/{FormGroup.spec.jsx => loginForms/FormGroups.spec.tsx} (63%) rename spec/javascripts/LoginPage/{HiddenInputs.spec.jsx => loginForms/HiddenInputs.spec.tsx} (84%) rename spec/javascripts/LoginPage/{Login3scaleForm.spec.jsx => loginForms/Login3scaleForm.spec.tsx} (58%) rename spec/javascripts/LoginPage/{RequestPasswordForm.spec.jsx => loginForms/RequestPasswordForm.spec.tsx} (53%) rename spec/javascripts/LoginPage/{SignupForm.spec.jsx => loginForms/SignupForm.spec.tsx} (61%) create mode 100644 spec/javascripts/LoginPage/loginForms/__snapshots__/ForgotCredentials.spec.tsx.snap create mode 100644 spec/javascripts/LoginPage/loginForms/__snapshots__/RequestPasswordForm.spec.tsx.snap create mode 100644 spec/javascripts/LoginPage/utils/formValidation.spec.ts delete mode 100644 spec/javascripts/MappingRules/PatternInput.spec.jsx delete mode 100644 spec/javascripts/MappingRules/components/HttpMethodSelect.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/HttpMethodSelect.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/IncrementByInput.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/IncrementByInput.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/IsLastCheckbox.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/IsLastCheckbox.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/MetricInput.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/MetricInput.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/NewMappingRule.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/NewMappingRule.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/PatternInput.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/PatternInput.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/PositionInput.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/PositionInput.spec.tsx delete mode 100644 spec/javascripts/MappingRules/components/RedirectUrlInput.spec.jsx create mode 100644 spec/javascripts/MappingRules/components/RedirectUrlInput.spec.tsx delete mode 100644 spec/javascripts/Metrics/components/BackendAPIIndexPage.spec.jsx create mode 100644 spec/javascripts/Metrics/components/BackendAPIIndexPage.spec.tsx rename spec/javascripts/Metrics/components/{IndexPage.spec.jsx => IndexPage.spec.tsx} (88%) rename spec/javascripts/Metrics/components/{MetricsTable.spec.jsx => MetricsTable.spec.tsx} (81%) delete mode 100644 spec/javascripts/Metrics/components/ProductIndexPage.spec.jsx create mode 100644 spec/javascripts/Metrics/components/ProductIndexPage.spec.tsx delete mode 100644 spec/javascripts/Navigation/ActiveMenuTitle.spec.jsx create mode 100644 spec/javascripts/Navigation/ActiveMenuTitle.spec.tsx rename spec/javascripts/Navigation/{ContextSelector.spec.jsx => ContextSelector.spec.tsx} (64%) rename spec/javascripts/Navigation/{VerticalNav.spec.jsx => VerticalNav.spec.tsx} (76%) create mode 100644 spec/javascripts/Navigation/__snapshots__/ContextSelector.spec.tsx.snap rename spec/javascripts/NewApplication/components/{ApplicationPlanSelect.spec.jsx => ApplicationPlanSelect.spec.tsx} (59%) rename spec/javascripts/NewApplication/components/{BuyerSelect.spec.jsx => BuyerSelect.spec.tsx} (68%) rename spec/javascripts/NewApplication/components/{NewApplicationForm.spec.jsx => NewApplicationForm.spec.tsx} (73%) rename spec/javascripts/NewApplication/components/{ProductSelect.spec.jsx => ProductSelect.spec.tsx} (72%) rename spec/javascripts/NewApplication/components/{ServicePlanSelect.spec.jsx => ServicePlanSelect.spec.tsx} (55%) delete mode 100644 spec/javascripts/NewService/NewServiceForm.spec.jsx delete mode 100644 spec/javascripts/NewService/ServiceDiscoveryForm.spec.jsx delete mode 100644 spec/javascripts/NewService/ServiceManualForm.spec.jsx create mode 100644 spec/javascripts/NewService/components/NewServiceForm.spec.tsx create mode 100644 spec/javascripts/NewService/components/ServiceDiscoveryForm.spec.tsx create mode 100644 spec/javascripts/NewService/components/ServiceManualForm.spec.tsx rename spec/javascripts/NewService/{ServiceSourceForm.spec.jsx => components/ServiceSourceForm.spec.tsx} (72%) rename spec/javascripts/NewService/formElements/{ErrorMessage.spec.jsx => ErrorMessage.spec.tsx} (51%) delete mode 100644 spec/javascripts/NewService/formElements/FormWrapper.spec.jsx create mode 100644 spec/javascripts/NewService/formElements/FormWrapper.spec.tsx rename spec/javascripts/NewService/formElements/{HiddenServiceDiscoveryInput.spec.jsx => HiddenServiceDiscoveryInput.spec.tsx} (89%) rename spec/javascripts/NewService/formElements/{Label.spec.jsx => Label.spec.tsx} (57%) rename spec/javascripts/NewService/formElements/{Select.spec.jsx => Select.spec.tsx} (60%) rename spec/javascripts/NewService/formElements/{ServiceDiscoveryListItems.spec.jsx => ServiceDiscoveryListItems.spec.tsx} (60%) rename spec/javascripts/NewService/formElements/{ServiceManualListItems.spec.jsx => ServiceManualListItems.spec.tsx} (80%) create mode 100644 spec/javascripts/NewService/formElements/__snapshots__/ServiceManualListItems.spec.tsx.snap rename spec/javascripts/PaymentGateways/{StripeFormWrapper.spec.jsx => StripeFormWrapper.spec.tsx} (74%) rename spec/javascripts/PaymentGateways/braintree/{BraintreeForm.spec.jsx => BraintreeForm.spec.tsx} (84%) rename spec/javascripts/PaymentGateways/braintree/components/{Input.spec.jsx => Input.spec.tsx} (52%) rename spec/javascripts/PaymentGateways/braintree/components/{Label.spec.jsx => Label.spec.tsx} (71%) delete mode 100644 spec/javascripts/PaymentGateways/braintree/components/ListItem.spec.jsx create mode 100644 spec/javascripts/PaymentGateways/braintree/components/ListItem.spec.tsx rename spec/javascripts/Plans/components/{ChangePlanSelectCard.spec.jsx => ChangePlanSelectCard.spec.tsx} (59%) rename spec/javascripts/Plans/components/{DefaultPlanSelectCard.spec.jsx => DefaultPlanSelectCard.spec.tsx} (61%) rename spec/javascripts/Plans/components/{PlansTable.spec.jsx => PlansTable.spec.tsx} (52%) rename spec/javascripts/Plans/components/{PlansTableCard.spec.jsx => PlansTableCard.spec.tsx} (69%) create mode 100644 spec/javascripts/Policies/actions/OriginalPolicyChain.spec.ts delete mode 100644 spec/javascripts/Policies/actions/PolicyChain.spec.jsx create mode 100644 spec/javascripts/Policies/actions/PolicyChain.spec.ts create mode 100644 spec/javascripts/Policies/actions/PolicyConfig.spec.ts delete mode 100644 spec/javascripts/Policies/actions/PolicyRegistry.spec.jsx create mode 100644 spec/javascripts/Policies/actions/PolicyRegistry.spec.ts create mode 100644 spec/javascripts/Policies/actions/ThunkAction.spec.ts create mode 100644 spec/javascripts/Policies/actions/UISetting.spec.ts rename spec/javascripts/Policies/components/{HeaderButton.spec.jsx => HeaderButton.spec.tsx} (54%) create mode 100644 spec/javascripts/Policies/components/PoliciesWidget.spec.tsx delete mode 100644 spec/javascripts/Policies/components/PolicyChain.spec.jsx create mode 100644 spec/javascripts/Policies/components/PolicyChain.spec.tsx rename spec/javascripts/Policies/components/{PolicyChainHiddenInput.spec.jsx => PolicyChainHiddenInput.spec.tsx} (65%) rename spec/javascripts/Policies/components/{PolicyConfig.spec.jsx => PolicyConfig.spec.tsx} (63%) delete mode 100644 spec/javascripts/Policies/components/PolicyRegistry.spec.jsx create mode 100644 spec/javascripts/Policies/components/PolicyRegistry.spec.tsx create mode 100644 spec/javascripts/Policies/components/PolicyTile.spec.tsx create mode 100644 spec/javascripts/Policies/components/Root.spec.tsx create mode 100644 spec/javascripts/Policies/components/__snapshots__/HeaderButton.spec.tsx.snap delete mode 100644 spec/javascripts/Policies/middleware/PolicyChain.spec.jsx create mode 100644 spec/javascripts/Policies/middleware/PolicyChain.spec.ts create mode 100644 spec/javascripts/Policies/reducers/OriginalPolicyChain.spec.ts rename spec/javascripts/Policies/reducers/{PolicyChain.spec.jsx => PolicyChain.spec.ts} (89%) rename spec/javascripts/Policies/reducers/{PolicyConfig.spec.jsx => PolicyConfig.spec.ts} (82%) rename spec/javascripts/Policies/reducers/{PolicyRegistry.spec.jsx => PolicyRegistry.spec.ts} (83%) rename spec/javascripts/Policies/reducers/{UISettings.spec.jsx => UISettings.spec.ts} (98%) rename spec/javascripts/Policies/{util.spec.jsx => util.spec.ts} (85%) delete mode 100644 spec/javascripts/Products/components/BackendsUsedListCard.spec.jsx create mode 100644 spec/javascripts/Products/components/BackendsUsedListCard.spec.tsx rename spec/javascripts/Products/components/{IndexPage.spec.jsx => IndexPage.spec.tsx} (78%) rename spec/javascripts/QuickStarts/components/{QuickStartContainer.spec.jsx => QuickStartContainer.spec.tsx} (55%) rename spec/javascripts/QuickStarts/utils/{progressTracker.spec.js => progressTracker.spec.ts} (73%) rename spec/javascripts/QuickStarts/utils/{replaceLinksExtension.spec.js => replaceLinksExtension.spec.ts} (98%) create mode 100644 spec/javascripts/Settings/authentication-widget.spec.ts rename spec/javascripts/Settings/components/{AuthenticationSettingsFieldset.spec.jsx => AuthenticationSettingsFieldset.spec.tsx} (87%) rename spec/javascripts/Settings/components/Common/{FormCollection.spec.jsx => FormCollection.spec.tsx} (51%) create mode 100644 spec/javascripts/Settings/components/Common/FormFieldset.spec.tsx create mode 100644 spec/javascripts/Settings/components/Common/FormLegend.spec.tsx delete mode 100644 spec/javascripts/Settings/components/Common/RadioFieldset.spec.jsx create mode 100644 spec/javascripts/Settings/components/Common/RadioFieldset.spec.tsx delete mode 100644 spec/javascripts/Settings/components/Common/SelectGroup.spec.jsx create mode 100644 spec/javascripts/Settings/components/Common/SelectGroup.spec.tsx delete mode 100644 spec/javascripts/Settings/components/Common/TextInputGroup.spec.jsx create mode 100644 spec/javascripts/Settings/components/Common/TextInputGroup.spec.tsx rename spec/javascripts/Settings/components/Common/{TypeItemCombo.spec.jsx => TypeItemCombo.spec.tsx} (89%) create mode 100644 spec/javascripts/Settings/components/Common/__snapshots__/FormCollection.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/Common/__snapshots__/RadioFieldset.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/Common/__snapshots__/SelectGroup.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/Common/__snapshots__/TextInputGroup.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/Common/__snapshots__/TypeItemCombo.spec.tsx.snap rename spec/javascripts/Settings/components/{Form.spec.jsx => Form.spec.tsx} (54%) delete mode 100644 spec/javascripts/Settings/components/OidcFieldset.spec.jsx create mode 100644 spec/javascripts/Settings/components/OidcFieldset.spec.tsx create mode 100644 spec/javascripts/Settings/components/__snapshots__/AuthenticationSettingsFieldset.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/__snapshots__/Form.spec.tsx.snap create mode 100644 spec/javascripts/Settings/components/__snapshots__/OidcFieldset.spec.tsx.snap create mode 100644 spec/javascripts/Stats/buyer/stats_application.spec.ts delete mode 100644 spec/javascripts/Stats/inlinechart/inlineChart.spec.jsx create mode 100644 spec/javascripts/Stats/inlinechart/inlineChart.spec.tsx create mode 100644 spec/javascripts/Stats/lib/application_details.spec.ts create mode 100644 spec/javascripts/Stats/lib/application_metrics_source.spec.ts rename spec/javascripts/Stats/{applications_selector.spec.js => lib/applications_selector.spec.ts} (71%) rename spec/javascripts/Stats/{applications_table.spec.js => lib/applications_table.spec.ts} (61%) rename spec/javascripts/Stats/{average_metrics_source.spec.js => lib/average_metrics_source.spec.ts} (76%) rename spec/javascripts/Stats/{chart.spec.js => lib/chart.spec.ts} (100%) rename spec/javascripts/Stats/{chart_manager.spec.js => lib/chart_manager.spec.ts} (72%) rename spec/javascripts/Stats/{csv_link.spec.js => lib/csv_link.spec.ts} (73%) rename spec/javascripts/Stats/{menu.spec.js => lib/menu.spec.ts} (61%) rename spec/javascripts/Stats/{methods_table.spec.js => lib/methods_table.spec.ts} (65%) rename spec/javascripts/Stats/{metric.spec.js => lib/metric.spec.ts} (87%) rename spec/javascripts/Stats/{metrics_list.spec.js => lib/metrics_list.spec.ts} (76%) rename spec/javascripts/Stats/{metrics_selector.spec.js => lib/metrics_selector.spec.ts} (71%) rename spec/javascripts/Stats/{metrics_source.spec.js => lib/metrics_source.spec.ts} (53%) rename spec/javascripts/Stats/{series.spec.js => lib/series.spec.ts} (68%) rename spec/javascripts/Stats/{source.spec.js => lib/source.spec.ts} (79%) create mode 100644 spec/javascripts/Stats/lib/source_collector.spec.ts rename spec/javascripts/Stats/{state.spec.js => lib/state.spec.ts} (72%) create mode 100644 spec/javascripts/Stats/lib/stats_helpers.spec.ts rename spec/javascripts/Stats/{store.spec.js => lib/store.spec.ts} (75%) create mode 100644 spec/javascripts/Stats/lib/top_apps_help_text.spec.ts rename spec/javascripts/Stats/{top_apps_source_collector.spec.js => lib/top_apps_source_collector.spec.ts} (79%) rename spec/javascripts/Stats/{usage_chart.spec.js => lib/usage_chart.spec.ts} (77%) create mode 100644 spec/javascripts/Stats/provider/stats_response_codes.spec.ts rename spec/javascripts/Stats/{stats_top_apps.spec.js => provider/stats_top_apps.spec.ts} (86%) delete mode 100644 spec/javascripts/Stats/source_collector.spec.js delete mode 100644 spec/javascripts/Stats/stats_helpers.spec.js delete mode 100644 spec/javascripts/Stats/stats_response_codes.spec.js delete mode 100644 spec/javascripts/Stats/top_apps_help_text.spec.js delete mode 100644 spec/javascripts/Users/components/FeaturesFieldset.spec.jsx create mode 100644 spec/javascripts/Users/components/FeaturesFieldset.spec.tsx delete mode 100644 spec/javascripts/Users/components/PermissionsForm.spec.jsx create mode 100644 spec/javascripts/Users/components/PermissionsForm.spec.tsx rename spec/javascripts/Users/components/{RoleRadioGroup.spec.jsx => RoleRadioGroup.spec.tsx} (50%) delete mode 100644 spec/javascripts/Users/components/ServicesFieldset.spec.jsx create mode 100644 spec/javascripts/Users/components/ServicesFieldset.spec.tsx rename spec/javascripts/Users/utils/{utils.spec.jsx => utils.spec.ts} (58%) create mode 100644 spec/javascripts/__mocks__/react-sortable-hoc.js create mode 100644 spec/javascripts/__mocks__/utilities/CSRFToken.tsx rename spec/javascripts/services/{index.spec.js => index.spec.ts} (77%) rename spec/javascripts/services/{migrate.spec.js => migrate.spec.ts} (100%) rename spec/javascripts/{setupTests.js => setupTests.ts} (83%) create mode 100644 spec/javascripts/utilities/CSRFToken.spec.tsx create mode 100644 spec/javascripts/utilities/ajax.spec.ts create mode 100644 spec/javascripts/utilities/confirm-dialog.spec.ts create mode 100644 spec/javascripts/utilities/createReactWrapper.spec.tsx create mode 100644 spec/javascripts/utilities/fetchData.spec.ts create mode 100644 spec/javascripts/utilities/flash.spec.ts rename spec/javascripts/utilities/{isActiveTab.spec.js => isActiveTab.spec.ts} (53%) rename spec/javascripts/utilities/{json-utils.spec.jsx => json-utils.spec.ts} (81%) create mode 100644 spec/javascripts/utilities/paginateCollection.spec.ts create mode 100644 spec/javascripts/utilities/patternfly-utils.spec.tsx delete mode 100644 spec/javascripts/utilities/toggle.spec.js create mode 100644 spec/javascripts/utilities/toggle.spec.ts create mode 100644 spec/javascripts/utilities/useClickOutside.spec.tsx create mode 100644 spec/javascripts/utilities/useSearchInputEffect.spec.tsx delete mode 100644 spec/javascripts/utilities/utils.spec.jsx create mode 100644 tsconfig.json create mode 100644 tsconfig.prod.json diff --git a/.babelrc b/.babelrc index 9818ff3106..f92e629aaa 100644 --- a/.babelrc +++ b/.babelrc @@ -1,28 +1,8 @@ { "plugins": [ - "@babel/plugin-syntax-dynamic-import", - "@babel/plugin-transform-runtime", - "@babel/plugin-proposal-class-properties", - "@babel/plugin-transform-template-literals", - "@babel/plugin-proposal-object-rest-spread", - "@babel/plugin-transform-destructuring" ], "presets": [ - [ - "@babel/preset-env", - { - "useBuiltIns": "entry", - "corejs": "2", - "targets": { - "node": "current", - "ie": "11", - "firefox": "67", - "chrome": "75", - "edge": "44" - } - } - ], - "@babel/react", - "@babel/flow" + "@babel/preset-env", + "@babel/react" ] } diff --git a/.circleci/config.yml b/.circleci/config.yml index 45b39153ac..a0960f54a5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,17 +28,10 @@ store-log-artifacts: &store-log-artifacts path: log destination: log -flow-type-key: &flow-typed-cache-key flow-typed-{{ checksum "yarn.lock" }}-5 npm-cache-key: &npm-cache-key node-v10-{{ checksum "yarn.lock" }}-5 bundle-cache-key: &bundle-cache-key v2-bundler-gems-{{ .Environment.DB }}-{{ arch }}-{{ .Branch }}-{{ checksum "Gemfile.lock" }} assets-cache-key: &assets-cache-key v1-asset-cache-{{ checksum "tmp/assets_related_checksums" }} -save-flow-typed-cache: &save-flow-typed-cache - save_cache: - key: *flow-typed-cache-key - paths: - - ./flow-typed - restore-npm-cache: &restore-npm-cache restore_cache: key: *npm-cache-key @@ -48,11 +41,6 @@ save-npm-cache: &save-npm-cache key: *npm-cache-key paths: - ./node_modules - - ./flow-typed - -restore-flow-typed-cache: &restore-flow-typed-cache - restore_cache: - key: *flow-typed-cache-key save-assets-cache: &save-assets-cache save_cache: @@ -497,13 +485,10 @@ jobs: command: | bundle exec rake doc:swagger:validate:all bundle exec rake doc:swagger:generate:all - - *restore-flow-typed-cache - run: - name: Eslint & Flow + name: Eslint command: | - yarn flow:install - yarn lint - - *save-flow-typed-cache + yarn ci:lint - store_artifacts: path: doc/licenses destination: licenses diff --git a/.codeclimate.yml b/.codeclimate.yml index ad1b74e6d3..33a0f9b15e 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -17,10 +17,12 @@ plugins: enabled: true eslint: enabled: true - channel: "eslint-6" + channel: "eslint-7" # Should match the one in package.json config: config: .eslintrc extensions: + - .ts + - .tsx - .js - .jsx csslint: @@ -56,4 +58,3 @@ exclude_patterns: - "app/javascript/src/*/*/*.spec.*" - "bin/webpack*" - "**/node_modules/" - - "**/flow-typed" diff --git a/.dockerignore b/.dockerignore index ef6e35d495..ba15ffd0ed 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,7 +6,6 @@ .bin cookbooks node_modules -flow-typed assets/jspm_packages/*/* vendor/bundle .vagrant @@ -48,7 +47,6 @@ log/* **/*.swp **/.* !.eslintrc -!.flowconfig !.babelrc !.ruby-version.sample !Gemfile* diff --git a/.eslintignore b/.eslintignore index b98e42dc27..774eece87d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,19 +1,19 @@ -.circleci -.github -app/assets -bin -build -cdn -config -db -doc -features -lib -log -openshift -public -script -test -tmp -vendor -flow-typed +/.circleci +/.github +/app/assets +/bin +/build +/cdn +/config +/db +/doc +/features +/lib +/log +/openshift +/public +/script +/test +/tmp +/vendor +/app/javascript/packs/PF4Styles diff --git a/.eslintrc b/.eslintrc index f1c54a914c..b21868e50d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,95 +1,134 @@ { - "parser": "babel-eslint", + "root": true, + "parser": "@typescript-eslint/parser", "parserOptions": { - "sourceType": "module", - "allowImportExportEverywhere": false, - "codeFrame": false + "project": ["./tsconfig.json"], + "ecmaVersion": 6, + "ecmaFeatures": { + "impliedStrict": true, + "jsxPragma": null // Required by @typescript/eslint-parser + } }, "env": { "browser": true, - "node": true, "jest": true }, - "globals": { - "$": true - }, - "extends": "standard", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/all", + "plugin:react/all", + "plugin:import/recommended", + "plugin:import/typescript", + "./eslint-naming-conventions.json", + ], "plugins": [ - "flowtype", - "react" + "@typescript-eslint", + "import", + // "jsx-expressions" // TODO: requires eslint 8 ], "rules": { - "no-console": [ - "warn", - { - "allow": [ - "error" - ] - } - ], - "no-duplicate-imports": 0, - "react/sort-comp": [ - 2, - { - "order": [ - "type-annotations", - "static-methods", - "life-cycle", - "everything-else", - "render" - ] - } - ], - "react/no-unused-prop-types": 0, - "react/jsx-uses-react": 2, - "react/jsx-uses-vars": 2, - "react/react-in-jsx-scope": 2, - "flowtype/boolean-style": [ - 2, - "boolean" - ], - "flowtype/define-flow-type": 1, - "flowtype/generic-spacing": [ - 2, - "never" - ], - "flowtype/no-primitive-constructor-types": 2, - "flowtype/no-weak-types": 1, - "flowtype/object-type-delimiter": [ - 2, - "comma" - ], - "flowtype/require-valid-file-annotation": 2, - "flowtype/space-after-type-colon": [ - 2, - "always" - ], - "flowtype/space-before-generic-bracket": [ - 2, - "never" - ], - "flowtype/space-before-type-colon": [ - 2, - "never" - ], - "flowtype/union-intersection-spacing": [ - 2, - "always" - ], - "flowtype/use-flow-type": 1, - "flowtype/valid-syntax": 1, - // Workaround to bypass error: TypeError: Cannot read property 'range' of null - // See: https://github.com/babel/babel-eslint/issues/681#issuecomment-420663038 - // We should upgrade from babel-eslint (deprecated) to @babel/eslint-parser - "template-curly-spacing": "off", - "indent": "off" + // Override eslint:recommended + "object-curly-spacing": "off", // Disabled in favor of @typescript-eslint/object-curly-spacing + "array-callback-return": "error", + "no-duplicate-imports": "off", // Disabled in favor of @typescript-eslint/no-duplicate-imports + "no-console": ["warn", { "allow": ["error"] }], + "sort-imports": "off", // Disabled in favor of import/order + "semi": "off", // Disabled in favor of @typescript-eslint/semi + "no-multiple-empty-lines": ["error", { "max": 1 }], + "jsx-quotes": ["error", "prefer-double"], + "array-bracket-spacing": ["error", "never"], + // "eslint array-bracket-newline": ["error", { "multiline": true }], // TODO: requires eslint 8 + + // Override plugin:@typescript-eslint/all + "@typescript-eslint/object-curly-spacing": ["error", "always"], + "@typescript-eslint/quotes": ["error", "single", { "avoidEscape": true }], + "@typescript-eslint/indent": ["error", 2, { "SwitchCase": 1 }], + "@typescript-eslint/prefer-readonly-parameter-types": "off", + "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-type-alias": "off", + "@typescript-eslint/strict-boolean-expressions": "off", + "@typescript-eslint/no-magic-numbers": "off", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/promise-function-async": "off", + + // Override plugin:@typescript-eslint/recommended + "@typescript-eslint/semi": ["error", "never"], + "@typescript-eslint/no-unused-vars": 2, + "@typescript-eslint/consistent-type-imports": 2, + "@typescript-eslint/no-duplicate-imports": "error", + + // Override plugin:react/all + "react/destructuring-assignment": "off", + "react/forbid-component-props": "off", + "react/function-component-definition": "off", + "react/jsx-curly-newline": ["error", { "multiline": "forbid", "singleline": "forbid" }], + "react/jsx-filename-extension": [2, { "extensions": [".jsx", ".tsx"] }], + "react/jsx-handler-names": "off", + "react/jsx-indent-props": "off", + "react/jsx-indent": "off", + "react/jsx-max-depth": "off", + "react/jsx-max-props-per-line": ["error", { "maximum": 1, "when": "multiline" }], + "react/jsx-newline": "off", + "react/jsx-no-bind": "off", + "react/jsx-no-leaked-render": "off", + "react/jsx-no-literals": "off", + "react/jsx-one-expression-per-line": "off", + "react/jsx-sort-props": [2, { + "callbacksLast": true, + "shorthandFirst": true, + "reservedFirst": ["key"] + }], + "react/jsx-wrap-multilines": ["error", { + "declaration": "parens-new-line", + "assignment": "parens-new-line", + "return": "parens-new-line", + "arrow": "parens-new-line", + "condition": "parens-new-line", + "logical": "parens-new-line" + }], + "react/jsx-child-element-spacing": "warn", + "react/prop-types": "off", + "react/react-in-jsx-scope": "off", + "react/require-default-props": "off", + "react/no-set-state": "off", + "react/no-unescaped-entities": "warn", + + // From plugin import + "import/order": ["error", { + "warnOnUnassignedImports": true, + "groups": [["builtin", "external"], "internal", "index", "object", "type", ["parent", "sibling"]], + "pathGroups": [{ + "pattern": "utilities/**", + "group": "internal", + // "position": "after" // TODO: enable this once "distincGroup" is available to locate utilities at the bottom of this group + },{ + "pattern": "**/*.scss", + "group": "sibling", + }], + "newlines-between": "always", + // "distinctGroup": "false" // TODO: config not yet available. + }], + "import/newline-after-import": "error", + "import/no-relative-packages": "error", + + // From plugin jsx-expressions + // "jsx-expressions/strict-logical-expressions": "error", // Replaces rule "react/jsx-no-leaked-render" // TODO: requires eslint 8 }, "settings": { "react": { - "version": "detect" + "version": "detect" // React version. "detect" automatically picks the version you have installed. }, - "flowtype": { - "onlyFilesWithFlowAnnotation": true + "import/resolver": { + "typescript": true } - } + }, + "ignorePatterns": [ + "jest.config.js", + "spec/javascripts/setupTests.ts", + "spec/javascripts/__mocks__/", + "app/javascript/src/Stats" // We better avoid touching this module, eslint may automatically fix some of the errors and break it. + ] } diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index b4577536e7..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,22 +0,0 @@ -[ignore] -.*/__snapshots__/.* -/node_modules - -[include] -/app/javascript/ -/spec/javascripts/ - -[libs] -./app/javascript/src/Types/libs/libdefs.js -flow-typed - -[lints] - -[options] -emoji=true -experimental.const_params=true -max_header_tokens=1 -module.name_mapper='.*\(.s?css\)' -> 'empty/object' -module.name_mapper='.*\(.ya?ml\)' -> 'empty/object' -module.system=haste -module.name_mapper='^\(ActiveDocs\|Applications\|BackendApis\|ChangePassword\|Common\|EmailConfigurations\|Settings\|Dashboard\|Logic\|LoginPage\|Metrics\|MappingRules\|Navigation\|NewApplication\|Onboarding\|PaymentGateways\|Plans\|Policies\|Products\|QuickStarts\|services\|Stats\|Types\|Users\|utilities\|NewService\)\(.*\)$' -> '/app/javascript/src/\1/\2' diff --git a/.gitignore b/.gitignore index a90287e029..ac969b14c9 100644 --- a/.gitignore +++ b/.gitignore @@ -137,8 +137,6 @@ Gemfile.local # IDE local settings .vscode -# Typings -flow-typed config/cable.yml # Yarn @@ -148,3 +146,4 @@ config/cable.yml .pnp.* package-lock.json *.orig +yarn-error.log diff --git a/app/javascript/packs/ChangePassword.js b/app/javascript/packs/ChangePassword.js deleted file mode 100644 index 3640ef65d8..0000000000 --- a/app/javascript/packs/ChangePassword.js +++ /dev/null @@ -1,8 +0,0 @@ -import { ChangePasswordWrapper as ChangePassword } from 'ChangePassword' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const changePasswordContainer = document.getElementById('pf-login-page-container') - const changePasswordProps = safeFromJsonString(changePasswordContainer.dataset.changePasswordProps) - ChangePassword(changePasswordProps, 'pf-login-page-container') -}) diff --git a/app/javascript/packs/LoginPage.js b/app/javascript/packs/LoginPage.js deleted file mode 100644 index cc4979f4aa..0000000000 --- a/app/javascript/packs/LoginPage.js +++ /dev/null @@ -1,13 +0,0 @@ -import '@babel/polyfill' -import 'core-js/es7/object' - -import { safeFromJsonString } from 'utilities' -import { LoginPageWrapper } from 'LoginPage' - -document.addEventListener('DOMContentLoaded', () => { - const oldLoginWrapper = document.getElementById('old-login-page-wrapper') - oldLoginWrapper.removeChild(document.getElementById('old-login-page')) - const PFLoginPageContainer = document.getElementById('pf-login-page-container') - const loginPageProps = safeFromJsonString(PFLoginPageContainer.dataset.loginProps) - LoginPageWrapper(loginPageProps, 'pf-login-page-container') -}) diff --git a/app/javascript/packs/OAS3Autocomplete.js b/app/javascript/packs/OAS3Autocomplete.js deleted file mode 100644 index 43eb38a195..0000000000 --- a/app/javascript/packs/OAS3Autocomplete.js +++ /dev/null @@ -1,110 +0,0 @@ -// @flow - -import { fetchData } from 'utilities' -import type { - AccountData, - Param, - PathItemObject, - PathOperationObject, - ResponseBody, - SwaggerResponse -} from 'Types/SwaggerTypes' - -const X_DATA_ATTRIBUTE = 'x-data-threescale-name' - -const X_DATA_PARAMS_DESCRIPTIONS = { - user_keys: 'First user key from latest 5 applications', - app_ids: 'Latest 5 applications (across all accounts and services)', - app_keys: 'First application key from the latest five applications' -} - -const addAutocompleteToParam = (param: Param, accountData: AccountData): Param => { - const xDataKey = param[X_DATA_ATTRIBUTE] - const autocompleteData = accountData[xDataKey] - const paramHasAutocompleteData = autocompleteData && autocompleteData.length > 0 && - autocompleteData.every(param => param.name !== '') - - return paramHasAutocompleteData - ? { - ...param, - examples: autocompleteData.reduce((examples, item) => ( - [...examples, { summary: item.name, value: item.value }] - ), [{ summary: X_DATA_PARAMS_DESCRIPTIONS[xDataKey], value: '-' }]) - } - : param -} - -const injectParametersToPathOperation = (pathOperation: PathOperationObject, accountData: AccountData): PathOperationObject => { - const operationParameters = pathOperation.parameters - if (!operationParameters) return pathOperation - const parametersWithAutocompleteData = operationParameters.map(param => X_DATA_ATTRIBUTE in param ? addAutocompleteToParam(param, accountData) : param) - return { - ...pathOperation, - parameters: parametersWithAutocompleteData - } -} - -const injectAutocompleteToCommonParameters = (parameters: Array, accountData: AccountData): Array => parameters.map( - param => X_DATA_ATTRIBUTE in param ? addAutocompleteToParam(param, accountData) : param -) - -const injectParametersToPath = (path: PathItemObject, commonParameters?: Array = [], accountData: AccountData): PathItemObject => ( - Object.keys(path).reduce((updatedPath, item) => { - updatedPath[item] = (item === 'parameters' && commonParameters) - ? injectAutocompleteToCommonParameters(commonParameters, accountData) - // $FlowIgnore[incompatible-call] should be safe to assume correct type - // $FlowIgnore[incompatible-return] should be safe to assume correct type - : injectParametersToPathOperation(path[item], accountData) - return updatedPath - }, {}) -) - -const injectAutocompleteToResponseBody = (responseBody: ResponseBody | string, accountData: AccountData): ResponseBody | string => { - const res = (typeof responseBody !== 'string' && responseBody.paths && accountData) ? { - ...responseBody, - paths: Object.keys(responseBody.paths).reduce( - (paths, path) => { - const commonParameters = responseBody.paths[path].parameters - // $FlowFixMe[incompatible-call] should safe to assume it is PathItemObject - paths[path] = injectParametersToPath(responseBody.paths[path], commonParameters, accountData) - return paths - }, {}) - } : responseBody - return res -} - -const injectServerToResponseBody = (responseBody: ResponseBody | string, serviceEndpoint: string): ResponseBody | string => { - if (typeof responseBody === 'string') { - return responseBody - } - - const originalServers = responseBody.servers || [] - const servers = serviceEndpoint ? [{ url: serviceEndpoint }] : originalServers - - return { - ...responseBody, - // $FlowFixMe[incompatible-return] should be safe to assume correct type - servers - } -} - -export const autocompleteOAS3 = async (response: SwaggerResponse, accountDataUrl: string, serviceEndpoint: string): Promise => { - const bodyWithServer = injectServerToResponseBody(response.body, serviceEndpoint) - const body = await fetchData(accountDataUrl) - .then(data => ( - data.results - ? injectAutocompleteToResponseBody(bodyWithServer, data.results) - : bodyWithServer - )) - .catch(error => { - console.error(error) - return bodyWithServer - }) - - return { - ...response, - body, - data: JSON.stringify(body), - text: JSON.stringify(body) - } -} diff --git a/app/javascript/packs/PF4Styles/base.js b/app/javascript/packs/PF4Styles/base.js index 9af9247f99..ca1a74ac45 100644 --- a/app/javascript/packs/PF4Styles/base.js +++ b/app/javascript/packs/PF4Styles/base.js @@ -1,2 +1 @@ -import '@babel/polyfill' import 'patternflyStyles/pf4Base' diff --git a/app/javascript/packs/RequestPasswordPage.js b/app/javascript/packs/RequestPasswordPage.js deleted file mode 100644 index d4d78cfbc0..0000000000 --- a/app/javascript/packs/RequestPasswordPage.js +++ /dev/null @@ -1,12 +0,0 @@ -import '@babel/polyfill' -import 'core-js/es7/object' - -import { RequestPasswordWrapper as RequestPassword } from 'LoginPage' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const containerId = 'pf-request-page-container' - const container = document.getElementById(containerId) - const requestPageProps = safeFromJsonString(container.dataset.requestProps) - RequestPassword(requestPageProps, containerId) -}) diff --git a/app/javascript/packs/SignUpPage.js b/app/javascript/packs/SignUpPage.js deleted file mode 100644 index 665bec3213..0000000000 --- a/app/javascript/packs/SignUpPage.js +++ /dev/null @@ -1,17 +0,0 @@ -import '@babel/polyfill' -import 'core-js/es7/object' - -import { SignupPageWrapper } from 'LoginPage' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const PFLoginPageContainer = document.getElementById('pf-login-page-container') - - let oldLoginWrapper = document.getElementById('old-login-page-wrapper') - if (oldLoginWrapper.parentNode) { - oldLoginWrapper.parentNode.removeChild(oldLoginWrapper) - } - - const signupPageProps = safeFromJsonString(PFLoginPageContainer.dataset.signupProps) - SignupPageWrapper(signupPageProps, 'pf-login-page-container') -}) diff --git a/app/javascript/packs/StripeForm.js b/app/javascript/packs/StripeForm.js deleted file mode 100644 index 5465d9b6c6..0000000000 --- a/app/javascript/packs/StripeForm.js +++ /dev/null @@ -1,15 +0,0 @@ -import { StripeFormWrapper } from 'PaymentGateways' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const containerId = 'stripe-form-wrapper' - const containerDataset = document.getElementById(containerId).dataset - - StripeFormWrapper({ - stripePublishableKey: containerDataset.stripePublishableKey, - setupIntentSecret: containerDataset.setupIntentSecret, - billingAddressDetails: safeFromJsonString(containerDataset.billingAddress), - successUrl: containerDataset.successUrl, - isCreditCardStored: containerDataset.creditCardStored === 'true' - }, containerId) -}) diff --git a/app/javascript/packs/active_docs.js b/app/javascript/packs/active_docs.js deleted file mode 100644 index c2453929c7..0000000000 --- a/app/javascript/packs/active_docs.js +++ /dev/null @@ -1,16 +0,0 @@ -// We can define the 3scale plugins here and export the modified bundle -import SwaggerUI from 'swagger-ui' -import { autocompleteOAS3 } from './OAS3Autocomplete' -import 'swagger-ui/dist/swagger-ui.css' -import 'ActiveDocs/swagger-ui-3-patch.scss' - -const accountDataUrl = '/api_docs/account_data.json' - -window.SwaggerUI = (args, serviceEndpoint) => { - const responseInterceptor = (response) => autocompleteOAS3(response, accountDataUrl, serviceEndpoint) - - SwaggerUI({ - ...args, - responseInterceptor - }) -} diff --git a/app/javascript/packs/active_docs.ts b/app/javascript/packs/active_docs.ts new file mode 100644 index 0000000000..43b9dd2c84 --- /dev/null +++ b/app/javascript/packs/active_docs.ts @@ -0,0 +1,18 @@ +// We can define the 3scale plugins here and export the modified bundle +import SwaggerUI from 'swagger-ui' +import 'swagger-ui/dist/swagger-ui.css' + +import { autocompleteOAS3 } from 'ActiveDocs/OAS3Autocomplete' + +import 'ActiveDocs/swagger-ui-3-patch.scss' + +const accountDataUrl = '/api_docs/account_data.json' + +window.SwaggerUI = (args: SwaggerUI.SwaggerUIOptions, serviceEndpoint: string) => { + const responseInterceptor = (response: SwaggerUI.Response) => autocompleteOAS3(response, accountDataUrl, serviceEndpoint) + + SwaggerUI({ + ...args, + responseInterceptor + } as SwaggerUI.SwaggerUIOptions) +} diff --git a/app/javascript/packs/add_backend_usage.js b/app/javascript/packs/add_backend_usage.ts similarity index 66% rename from app/javascript/packs/add_backend_usage.js rename to app/javascript/packs/add_backend_usage.ts index 039523b2b7..5d5346ccd3 100644 --- a/app/javascript/packs/add_backend_usage.js +++ b/app/javascript/packs/add_backend_usage.ts @@ -1,7 +1,5 @@ -// @flow - -import { AddBackendFormWrapper } from 'BackendApis' -import { safeFromJsonString } from 'utilities' +import { AddBackendFormWrapper } from 'BackendApis/components/AddBackendForm' +import { safeFromJsonString } from 'utilities/json-utils' import type { Backend } from 'Types' @@ -11,14 +9,14 @@ document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const { url, backendsPath, backendApiId } = dataset + const { url = '', backendsPath = '', backendApiId } = dataset - const backends = safeFromJsonString(dataset.backends) || [] - const backend = backends.find(b => String(b.id) === backendApiId) || null + const backends = safeFromJsonString(dataset.backends) ?? [] + const backend = backends.find(b => String(b.id) === backendApiId) ?? null const inlineErrors = safeFromJsonString(dataset.inlineErrors) || null AddBackendFormWrapper({ diff --git a/app/javascript/packs/api_selector.js b/app/javascript/packs/api_selector.js deleted file mode 100644 index a9e42979fe..0000000000 --- a/app/javascript/packs/api_selector.js +++ /dev/null @@ -1,11 +0,0 @@ -import { ContextSelectorWrapper } from 'Navigation/components/ContextSelector' - -const containerId = 'api_selector' - -document.addEventListener('DOMContentLoaded', function () { - const apiSelector = document.getElementById(containerId) - - ContextSelectorWrapper({ - ...apiSelector.dataset - }, containerId) -}) diff --git a/app/javascript/packs/api_selector.ts b/app/javascript/packs/api_selector.ts new file mode 100644 index 0000000000..d807b207a1 --- /dev/null +++ b/app/javascript/packs/api_selector.ts @@ -0,0 +1,23 @@ +import { ContextSelectorWrapper } from 'Navigation/components/ContextSelector' + +import type { Menu } from 'Types/NavigationTypes' + +const containerId = 'api_selector' + +document.addEventListener('DOMContentLoaded', function () { + const apiSelector = document.getElementById(containerId) + + if (!apiSelector) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { activeMenu, audienceLink, settingsLink = '', productsLink = '', backendsLink = '' } = apiSelector.dataset + + ContextSelectorWrapper({ + activeMenu: activeMenu as Menu, + audienceLink, + settingsLink, + productsLink, + backendsLink + }, containerId) +}) diff --git a/app/javascript/packs/backend_api_metrics_index.js b/app/javascript/packs/backend_api_metrics_index.ts similarity index 69% rename from app/javascript/packs/backend_api_metrics_index.js rename to app/javascript/packs/backend_api_metrics_index.ts index 277967de28..37a8884aa9 100644 --- a/app/javascript/packs/backend_api_metrics_index.js +++ b/app/javascript/packs/backend_api_metrics_index.ts @@ -1,6 +1,4 @@ -// @flow - -import { BackendAPIIndexPageWrapper } from 'Metrics' +import { BackendAPIIndexPageWrapper } from 'Metrics/components/BackendAPIIndexPage' import { safeFromJsonString } from 'utilities/json-utils' import type { Metric } from 'Types' @@ -15,9 +13,9 @@ document.addEventListener('DOMContentLoaded', () => { } const { dataset } = container - const { addMappingRulePath, createMetricPath, mappingRulesPath } = dataset - const metrics = safeFromJsonString>(dataset.metrics) || [] - const metricsCount = safeFromJsonString(dataset.metricsCount) || metrics.length + const { addMappingRulePath = '', createMetricPath = '', mappingRulesPath = '' } = dataset + const metrics = safeFromJsonString(dataset.metrics) ?? [] + const metricsCount = safeFromJsonString(dataset.metricsCount) ?? metrics.length BackendAPIIndexPageWrapper({ addMappingRulePath, diff --git a/app/javascript/packs/backend_apis_index.js b/app/javascript/packs/backend_apis_index.ts similarity index 53% rename from app/javascript/packs/backend_apis_index.js rename to app/javascript/packs/backend_apis_index.ts index 2f9e9e8065..acfd1093ef 100644 --- a/app/javascript/packs/backend_apis_index.js +++ b/app/javascript/packs/backend_apis_index.ts @@ -1,7 +1,5 @@ -// @flow - import { BackendsIndexPageWrapper } from 'BackendApis/components/IndexPage' -import { safeFromJsonString } from 'utilities' +import { safeFromJsonString } from 'utilities/json-utils' import type { Backend } from 'BackendApis/types' @@ -11,14 +9,14 @@ document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } - const { newBackendPath, backends, backendsCount } = container.dataset + const { newBackendPath = '', backends, backendsCount } = container.dataset BackendsIndexPageWrapper({ newBackendPath, - backends: safeFromJsonString(backends) || [], - backendsCount: safeFromJsonString(backendsCount) || 0 + backends: safeFromJsonString(backends) ?? [], + backendsCount: safeFromJsonString(backendsCount) ?? 0 }, containerId) }) diff --git a/app/javascript/packs/backends_used_list.js b/app/javascript/packs/backends_used_list.js deleted file mode 100644 index c53561fbaa..0000000000 --- a/app/javascript/packs/backends_used_list.js +++ /dev/null @@ -1,22 +0,0 @@ -// @flow - -import { BackendsUsedListCardWrapper } from 'Products' -import { safeFromJsonString } from 'utilities' - -import type { CompactListItem } from 'Common' - -const containerId = 'backends-used-list-container' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById(containerId) - - if (!container) { - return - } - - const { backends } = container.dataset - - BackendsUsedListCardWrapper({ - backends: safeFromJsonString>(backends) || [] - }, containerId) -}) diff --git a/app/javascript/packs/backends_used_list.ts b/app/javascript/packs/backends_used_list.ts new file mode 100644 index 0000000000..bb7e694831 --- /dev/null +++ b/app/javascript/packs/backends_used_list.ts @@ -0,0 +1,20 @@ +import { BackendsUsedListCardWrapper } from 'Products/components/BackendsUsedListCard' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { CompactListItem } from 'Common/components/CompactListCard' + +const containerId = 'backends-used-list-container' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { backends } = container.dataset + + BackendsUsedListCardWrapper({ + backends: safeFromJsonString(backends) ?? [] + }, containerId) +}) diff --git a/app/javascript/packs/braintree_customer_form.js b/app/javascript/packs/braintree_customer_form.js deleted file mode 100644 index 6ae2d55ee1..0000000000 --- a/app/javascript/packs/braintree_customer_form.js +++ /dev/null @@ -1,35 +0,0 @@ -import { - BraintreeFormWrapper, - createBraintreeClient -} from 'PaymentGateways' -import client from 'braintree-web/client' -import { safeFromJsonString } from 'utilities/json-utils' - -const CONTAINER_ID = 'braintree-form-wrapper' - -document.addEventListener('DOMContentLoaded', async () => { - const container = document.getElementById(CONTAINER_ID) - if (!container) { - return - } - - const { clientToken, billingAddress, threeDSecureEnabled, formActionPath, countriesList, selectedCountryCode } = container.dataset - const billingAddressParsed = safeFromJsonString(billingAddress) || {} - for (let key in billingAddressParsed) { - if (billingAddressParsed[key] === null) { - billingAddressParsed[key] = '' - } - } - const braintreeClient = await createBraintreeClient(client, clientToken) - - const props = { - braintreeClient, - formActionPath, - countriesList, - selectedCountryCode, - billingAddress: billingAddressParsed, - threeDSecureEnabled: threeDSecureEnabled === 'true' - } - - BraintreeFormWrapper(props, CONTAINER_ID) -}) diff --git a/app/javascript/packs/braintree_customer_form.ts b/app/javascript/packs/braintree_customer_form.ts new file mode 100644 index 0000000000..d97db9427c --- /dev/null +++ b/app/javascript/packs/braintree_customer_form.ts @@ -0,0 +1,38 @@ +import { client } from 'braintree-web' + +import { createBraintreeClient } from 'PaymentGateways/braintree/braintree' +import { BraintreeFormWrapper } from 'PaymentGateways/braintree/BraintreeForm' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Client } from 'braintree-web' +import type { BillingAddressData } from 'PaymentGateways/braintree/types' + +const CONTAINER_ID = 'braintree-form-wrapper' + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +document.addEventListener('DOMContentLoaded', async () => { + const container = document.getElementById(CONTAINER_ID) + if (!container) { + throw new Error('The target ID was not found: ' + CONTAINER_ID) + } + + const { clientToken, threeDSecureEnabled, formActionPath, countriesList, selectedCountryCode } = container.dataset as Record + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME: too much assumption here + const billingAddress = safeFromJsonString(container.dataset.billingAddress)! + for (const key in billingAddress) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- FIXME + if (billingAddress[key as keyof BillingAddressData] === null) { + billingAddress[key as keyof BillingAddressData] = '' + } + } + const braintreeClient = await createBraintreeClient(client, clientToken) as Client + + BraintreeFormWrapper({ + braintreeClient, + formActionPath: formActionPath, + countriesList: countriesList, + selectedCountryCode: selectedCountryCode, + billingAddress, + threeDSecureEnabled: threeDSecureEnabled === 'true' + }, CONTAINER_ID) +}) diff --git a/app/javascript/packs/change_password.ts b/app/javascript/packs/change_password.ts new file mode 100644 index 0000000000..1952823726 --- /dev/null +++ b/app/javascript/packs/change_password.ts @@ -0,0 +1,21 @@ +import { ChangePasswordWrapper } from 'ChangePassword/components/ChangePassword' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'ChangePassword/components/ChangePassword' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'pf-login-page-container' + const changePasswordContainer = document.getElementById(containerId) + + if (!changePasswordContainer) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { lostPasswordToken, url, errors } = safeFromJsonString(changePasswordContainer.dataset.changePasswordProps) ?? {} + + ChangePasswordWrapper({ + lostPasswordToken, + url, + errors + }, 'pf-login-page-container') +}) diff --git a/app/javascript/packs/change_plan_select.js b/app/javascript/packs/change_plan_select.ts similarity index 53% rename from app/javascript/packs/change_plan_select.js rename to app/javascript/packs/change_plan_select.ts index faf69fcffe..97f1fb8eae 100644 --- a/app/javascript/packs/change_plan_select.js +++ b/app/javascript/packs/change_plan_select.ts @@ -1,21 +1,19 @@ -// @flow +import { ChangePlanSelectCardWrapper } from 'Plans/components/ChangePlanSelectCard' +import { safeFromJsonString } from 'utilities/json-utils' -import { ChangePlanSelectCardWrapper } from 'Plans' -import { safeFromJsonString } from 'utilities' - -import type { Record as Plan } from 'Types' +import type { IRecord as Plan } from 'Types' document.addEventListener('DOMContentLoaded', () => { const containerId = 'change_plan_select' const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const applicationPlans = safeFromJsonString(dataset.applicationPlans) || [] - const path: string = dataset.path + const applicationPlans = safeFromJsonString(dataset.applicationPlans) ?? [] + const path: string = dataset.path ?? '' ChangePlanSelectCardWrapper({ applicationPlans, diff --git a/app/javascript/packs/dashboard.js b/app/javascript/packs/dashboard.ts similarity index 100% rename from app/javascript/packs/dashboard.js rename to app/javascript/packs/dashboard.ts diff --git a/app/javascript/packs/dashboard_backends_widget.js b/app/javascript/packs/dashboard_backends_widget.ts similarity index 50% rename from app/javascript/packs/dashboard_backends_widget.js rename to app/javascript/packs/dashboard_backends_widget.ts index 9034d9488b..4b83e61c7e 100644 --- a/app/javascript/packs/dashboard_backends_widget.js +++ b/app/javascript/packs/dashboard_backends_widget.ts @@ -1,12 +1,19 @@ import { BackendsWidgetWrapper } from 'Dashboard/components/BackendsWidget' -import { safeFromJsonString } from 'utilities' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'Dashboard/components/BackendsWidget' const containerId = 'backends-widget' document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) - const { newBackendPath, backendsPath, backends } = safeFromJsonString(container.dataset.backendsWidget) + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME: we need some default values or something + const { newBackendPath, backendsPath, backends } = safeFromJsonString(container.dataset.backendsWidget)! BackendsWidgetWrapper({ newBackendPath, diff --git a/app/javascript/packs/dashboard_products_widget.js b/app/javascript/packs/dashboard_products_widget.js deleted file mode 100644 index 5ea0508a25..0000000000 --- a/app/javascript/packs/dashboard_products_widget.js +++ /dev/null @@ -1,16 +0,0 @@ -import { ProductsWidgetWrapper } from 'Dashboard/components/ProductsWidget' -import { safeFromJsonString } from 'utilities' - -const containerId = 'products-widget' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById(containerId) - - const { newProductPath, productsPath, products } = safeFromJsonString(container.dataset.productsWidget) - - ProductsWidgetWrapper({ - newProductPath, - productsPath, - products - }, containerId) -}) diff --git a/app/javascript/packs/dashboard_products_widget.ts b/app/javascript/packs/dashboard_products_widget.ts new file mode 100644 index 0000000000..7cf55a7549 --- /dev/null +++ b/app/javascript/packs/dashboard_products_widget.ts @@ -0,0 +1,23 @@ +import { ProductsWidgetWrapper } from 'Dashboard/components/ProductsWidget' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'Dashboard/components/ProductsWidget' + +const containerId = 'products-widget' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME: we need to give some default values or something + const { newProductPath, productsPath, products } = safeFromJsonString(container.dataset.productsWidget)! + + ProductsWidgetWrapper({ + newProductPath, + productsPath, + products + }, containerId) +}) diff --git a/app/javascript/packs/default_plan_selector.js b/app/javascript/packs/default_plan_selector.ts similarity index 50% rename from app/javascript/packs/default_plan_selector.js rename to app/javascript/packs/default_plan_selector.ts index 4544db9c66..e956ffa072 100644 --- a/app/javascript/packs/default_plan_selector.js +++ b/app/javascript/packs/default_plan_selector.ts @@ -1,22 +1,20 @@ -// @flow +import { DefaultPlanSelectCardWrapper } from 'Plans/components/DefaultPlanSelectCard' +import { safeFromJsonString } from 'utilities/json-utils' -import { DefaultPlanSelectCardWrapper } from 'Plans' -import { safeFromJsonString } from 'utilities' - -import type { Record as Plan } from 'Types' +import type { IRecord as Plan } from 'Types' document.addEventListener('DOMContentLoaded', () => { const containerId = 'default_plan' const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const plans = safeFromJsonString(dataset.plans) || [] - const initialDefaultPlan = safeFromJsonString(dataset.currentPlan) || null - const path: string = dataset.path + const plans = safeFromJsonString(dataset.plans) ?? [] + const initialDefaultPlan = safeFromJsonString(dataset.currentPlan) ?? null + const path = dataset.path ?? '' DefaultPlanSelectCardWrapper({ initialDefaultPlan, diff --git a/app/javascript/packs/email_configurations/edit.js b/app/javascript/packs/email_configurations/edit.ts similarity index 88% rename from app/javascript/packs/email_configurations/edit.js rename to app/javascript/packs/email_configurations/edit.ts index 943d891dde..d6677b3886 100644 --- a/app/javascript/packs/email_configurations/edit.js +++ b/app/javascript/packs/email_configurations/edit.ts @@ -1,5 +1,3 @@ -// @flow - import { EditPageWrapper } from 'EmailConfigurations/components/EditPage' import { safeFromJsonString } from 'utilities/json-utils' @@ -10,11 +8,11 @@ document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const { url } = dataset + const { url = '' } = dataset const emailConfiguration = safeFromJsonString(dataset.emailConfiguration) if (!emailConfiguration) { diff --git a/app/javascript/packs/email_configurations/index.js b/app/javascript/packs/email_configurations/index.ts similarity index 76% rename from app/javascript/packs/email_configurations/index.js rename to app/javascript/packs/email_configurations/index.ts index b351f5dc87..376746be17 100644 --- a/app/javascript/packs/email_configurations/index.js +++ b/app/javascript/packs/email_configurations/index.ts @@ -1,7 +1,5 @@ -// @flow - import { IndexPageWrapper } from 'EmailConfigurations/components/IndexPage' -import { safeFromJsonString } from 'utilities' +import { safeFromJsonString } from 'utilities/json-utils' import type { EmailConfiguration } from 'EmailConfigurations/types' @@ -10,14 +8,14 @@ document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const emailConfigurations = safeFromJsonString(dataset.emailConfigurations) || [] - const emailConfigurationsCount = safeFromJsonString(dataset.emailConfigurationsCount) || 0 - const newEmailConfigurationPath = dataset.newEmailConfigurationPath + const emailConfigurations = safeFromJsonString(dataset.emailConfigurations) ?? [] + const emailConfigurationsCount = safeFromJsonString(dataset.emailConfigurationsCount) ?? 0 + const newEmailConfigurationPath = dataset.newEmailConfigurationPath ?? '' IndexPageWrapper({ emailConfigurations, diff --git a/app/javascript/packs/email_configurations/new.js b/app/javascript/packs/email_configurations/new.ts similarity index 88% rename from app/javascript/packs/email_configurations/new.js rename to app/javascript/packs/email_configurations/new.ts index f225d62add..ac46522674 100644 --- a/app/javascript/packs/email_configurations/new.js +++ b/app/javascript/packs/email_configurations/new.ts @@ -1,5 +1,3 @@ -// @flow - import { NewPageWrapper } from 'EmailConfigurations/components/NewPage' import { safeFromJsonString } from 'utilities/json-utils' @@ -10,11 +8,11 @@ document.addEventListener('DOMContentLoaded', () => { const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } const { dataset } = container - const { url } = dataset + const { url = '' } = dataset const emailConfiguration = safeFromJsonString(dataset.emailConfiguration) if (!emailConfiguration) { diff --git a/app/javascript/packs/inlineChart.js b/app/javascript/packs/inlineChart.js deleted file mode 100644 index b4ee9f588a..0000000000 --- a/app/javascript/packs/inlineChart.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' -import { render } from 'react-dom' -import InlineChart from '../src/Stats/inlinechart/index' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById('mini-charts') - const allCharts = [...container.querySelectorAll('.charts')] - - function renderChart (chart) { - const currentChart = chart.querySelector('.inline-chart-container') - const props = { - endPoint: currentChart.dataset.endpoint, - metricName: currentChart.dataset.metricName, - title: currentChart.dataset.title, - unitPluralized: chart.dataset.unitPluralized - } - render(, currentChart) - } - - allCharts.forEach(chart => { - renderChart(chart) - }) -}) diff --git a/app/javascript/packs/inline_chart.tsx b/app/javascript/packs/inline_chart.tsx new file mode 100644 index 0000000000..23ad120af5 --- /dev/null +++ b/app/javascript/packs/inline_chart.tsx @@ -0,0 +1,32 @@ +import { render } from 'react-dom' + +import InlineChart from 'Stats/inlinechart' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'mini-charts' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const allCharts = container.querySelectorAll('.charts') + + function renderChart (chart: HTMLElement) { + const currentChart = chart.querySelector('.inline-chart-container') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: need to give some default values or something here + const { endpoint, metricName, title, unitPluralized } = currentChart!.dataset + render(( + + ), currentChart) + } + + allCharts.forEach(chart => { + renderChart(chart) + }) +}) diff --git a/app/javascript/packs/invoice_payment.js b/app/javascript/packs/invoice_payment.js deleted file mode 100644 index b2a186b8df..0000000000 --- a/app/javascript/packs/invoice_payment.js +++ /dev/null @@ -1,87 +0,0 @@ -import { loadStripe } from '@stripe/stripe-js' -import 'PaymentGateways/stripe/styles/stripe.scss' - -const style = { - base: { - color: '#32325d', - fontFamily: 'Arial, sans-serif', - fontSmoothing: 'antialiased', - fontSize: '16px', - '::placeholder': { - color: '#32325d' - } - }, - invalid: { - fontFamily: 'Arial, sans-serif', - color: '#fa755a', - iconColor: '#fa755a' - } -} - -document.addEventListener('DOMContentLoaded', async () => { - const dataset = document.querySelector('.stripe-form').dataset - const stripePublishableKey = dataset.publishableKey - const clientSecret = dataset.clientSecret - const form = document.querySelector('#payment-form') - const callbackForm = document.querySelector('#payment-callback-form') - const payButton = document.querySelector('#submit-payment') - const cardError = document.querySelector('#card-error') - const errorMsg = document.querySelector('#card-error') - const spinner = document.querySelector('#spinner') - const buttonText = document.querySelector('#button-text') - - const stripe = await loadStripe(stripePublishableKey) - const elements = stripe.elements() - const card = elements.create('card', { style }) - - const payWithCard = (stripe, card, clientSecret) => { - setLoading(true) - stripe.confirmCardPayment(clientSecret, { - payment_method: { - card: card - } - }).then(function (result) { - if (result.error) { - showError(result.error.message) - } else { - orderComplete(result.paymentIntent) - } - }) - } - - const orderComplete = (paymentIntent) => { - Object.keys(paymentIntent).forEach(key => { - const hiddenField = document.createElement('input') - hiddenField.type = 'hidden' - hiddenField.name = `payment_intent[${key}]` - hiddenField.value = paymentIntent[key] - callbackForm.appendChild(hiddenField) - }) - callbackForm.submit() - } - - const showError = (errorMsgText) => { - setLoading(false) - errorMsg.textContent = errorMsgText - setTimeout(() => { - errorMsg.textContent = '' - }, 4000) - } - - const setLoading = (isLoading) => { - payButton.disabled = isLoading - spinner.classList.toggle('hidden', !isLoading) - buttonText.classList.toggle('hidden', isLoading) - } - - payButton.disabled = true - card.mount('#card-element') - card.on('change', event => { - payButton.disabled = !event.complete - cardError.textContent = event.error ? event.error.message : '' - }) - form.addEventListener('submit', function (event) { - event.preventDefault() - payWithCard(stripe, card, clientSecret) - }) -}) diff --git a/app/javascript/packs/invoice_payment.ts b/app/javascript/packs/invoice_payment.ts new file mode 100644 index 0000000000..af1ad25415 --- /dev/null +++ b/app/javascript/packs/invoice_payment.ts @@ -0,0 +1,96 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion -- FIXME: good luck with that */ + +import { loadStripe } from '@stripe/stripe-js' + +import type { PaymentIntent, Stripe, StripeCardElement } from '@stripe/stripe-js' + +import 'PaymentGateways/stripe/components/StripeFormWrapper.scss' + +const style = { + base: { + color: '#32325d', + fontFamily: 'Arial, sans-serif', + fontSmoothing: 'antialiased', + fontSize: '16px', + '::placeholder': { + color: '#32325d' + } + }, + invalid: { + fontFamily: 'Arial, sans-serif', + color: '#fa755a', + iconColor: '#fa755a' + } +} + +// eslint-disable-next-line @typescript-eslint/no-misused-promises +document.addEventListener('DOMContentLoaded', async () => { + const dataset = document.querySelector('.stripe-form')!.dataset + const { stripePublishableKey = '', clientSecret = '' } = dataset + const form = document.querySelector('#payment-form')! + const callbackForm = document.querySelector('#payment-callback-form')! + const payButton = document.querySelector('#submit-payment')! + const cardError = document.querySelector('#card-error')! + const errorMsg = document.querySelector('#card-error')! + const spinner = document.querySelector('#spinner')! + const buttonText = document.querySelector('#button-text')! + + const stripe = await loadStripe(stripePublishableKey)! + const elements = stripe!.elements() + const card = elements.create('card', { style }) + + // eslint-disable-next-line @typescript-eslint/no-shadow + const payWithCard = (stripe: Stripe, card: StripeCardElement, clientSecret: string) => { + setLoading(true) + void stripe.confirmCardPayment(clientSecret, { + // eslint-disable-next-line @typescript-eslint/naming-convention -- Stripe API + payment_method: { + card: card + } + }).then(function (result) { + if (result.error) { + showError(result.error.message) + } else { + orderComplete(result.paymentIntent) + } + }) + } + + const orderComplete = (paymentIntent: PaymentIntent) => { + Object.keys(paymentIntent).forEach(key => { + const hiddenField = document.createElement('input') + hiddenField.type = 'hidden' + hiddenField.name = `payment_intent[${key}]` + // @ts-expect-error FIXME: no idea where this comes from + hiddenField.value = paymentIntent[key] as string + callbackForm.appendChild(hiddenField) + }) + callbackForm.submit() + } + + const showError = (errorMsgText = '') => { + setLoading(false) + errorMsg.textContent = errorMsgText + setTimeout(() => { + errorMsg.textContent = '' + }, 4000) + } + + const setLoading = (isLoading: boolean) => { + payButton.disabled = isLoading + spinner.classList.toggle('hidden', !isLoading) + buttonText.classList.toggle('hidden', isLoading) + } + + payButton.disabled = true + card.mount('#card-element') + card.on('change', event => { + payButton.disabled = !event.complete + cardError.textContent = event.error?.message ?? '' + }) + form.addEventListener('submit', function (event) { + event.preventDefault() + // @ts-expect-error FIXME: we can't simply assume stripe instance will be there + payWithCard(stripe, card, clientSecret) + }) +}) diff --git a/app/javascript/packs/load_stripe.js b/app/javascript/packs/load_stripe.ts similarity index 50% rename from app/javascript/packs/load_stripe.js rename to app/javascript/packs/load_stripe.ts index e8d3286f45..943a5a2c7a 100644 --- a/app/javascript/packs/load_stripe.js +++ b/app/javascript/packs/load_stripe.ts @@ -1 +1,2 @@ +// TODO: remove this pack import '@stripe/stripe-js' diff --git a/app/javascript/packs/login_page.ts b/app/javascript/packs/login_page.ts new file mode 100644 index 0000000000..08707e7849 --- /dev/null +++ b/app/javascript/packs/login_page.ts @@ -0,0 +1,24 @@ +import { safeFromJsonString } from 'utilities/json-utils' +import { LoginPageWrapper } from 'LoginPage/LoginPageWrapper' + +import type { Props } from 'LoginPage/LoginPageWrapper' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'pf-login-page-container' + + const oldLoginWrapper = document.getElementById('old-login-page-wrapper') + const oldLoginPage = document.getElementById('old-login-page') + if (oldLoginWrapper && oldLoginPage ) { + oldLoginWrapper.removeChild(oldLoginPage) + } + + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME + const loginPageProps = safeFromJsonString(container.dataset.loginProps)! + LoginPageWrapper(loginPageProps, containerId) +}) diff --git a/app/javascript/packs/navigation.js b/app/javascript/packs/navigation.js deleted file mode 100644 index e3bfe749bf..0000000000 --- a/app/javascript/packs/navigation.js +++ /dev/null @@ -1,42 +0,0 @@ -import '@babel/polyfill' - -import { toggleNavigation, hideAllToggleable } from 'Navigation/utils/toggle_navigation' - -document.addEventListener('DOMContentLoaded', () => { - let store = window.localStorage - const togglers = document.getElementsByClassName('u-toggler') - const vertNavTogglers = document.getElementsByClassName('vert-nav-toggle') - const eventOptions = { - capture: true, - passive: false, - useCapture: true - } - - function addClickEventToCollection (collection, handler) { - for (let item of collection) { - item.addEventListener('click', handler, eventOptions) - } - } - - document.body.addEventListener('click', function (e) { - if (e.target.type !== 'search') { - hideAllToggleable() - } - }, eventOptions) - - addClickEventToCollection(togglers, function (e) { - e.stopPropagation() - toggleNavigation(e.currentTarget) - e.preventDefault() - }) - - addClickEventToCollection(vertNavTogglers, function () { - const shouldVertNavCollapse = !JSON.parse(store.isVerticalNavCollapsed || false) - - document.querySelector('.vertical-nav') - .classList - .toggle('collapsed') - - store.isVerticalNavCollapsed = shouldVertNavCollapse - }) -}) diff --git a/app/javascript/packs/navigation.ts b/app/javascript/packs/navigation.ts new file mode 100644 index 0000000000..a9d4a39239 --- /dev/null +++ b/app/javascript/packs/navigation.ts @@ -0,0 +1,42 @@ +import { hideAllToggleable, toggleNavigation } from 'Navigation/utils/toggle_navigation' + +document.addEventListener('DOMContentLoaded', () => { + const togglers = document.getElementsByClassName('u-toggler') as HTMLCollectionOf + const vertNavTogglers = document.getElementsByClassName('vert-nav-toggle') as HTMLCollectionOf + const eventOptions = { + capture: true, + passive: false, + useCapture: true + } + + function addClickEventToCollection (collection: HTMLCollectionOf, handler: (e: Event) => void) { + for (const item of Array.from(collection)) { + item.addEventListener('click', handler, eventOptions) + } + } + + document.body.addEventListener('click', (e: Event) => { + if ((e.target as HTMLInputElement).type !== 'search') { + hideAllToggleable() + } + }, eventOptions) + + addClickEventToCollection(togglers, function (e: Event) { + e.stopPropagation() + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME: can we safely assume the target is there? Also, why currentTarget here but target above? + toggleNavigation(e.currentTarget!) + e.preventDefault() + }) + + addClickEventToCollection(vertNavTogglers, function () { + const store = window.localStorage + // @ts-expect-error FIXME: should or should not? Figure it out + const shouldVertNavCollapse = !JSON.parse((store.isVerticalNavCollapsed as string) || false) + + document.querySelector('.vertical-nav') + ?.classList + .toggle('collapsed') + + store.isVerticalNavCollapsed = shouldVertNavCollapse + }) +}) diff --git a/app/javascript/packs/new_application.js b/app/javascript/packs/new_application.ts similarity index 75% rename from app/javascript/packs/new_application.js rename to app/javascript/packs/new_application.ts index bb98d47b08..4044115278 100644 --- a/app/javascript/packs/new_application.js +++ b/app/javascript/packs/new_application.ts @@ -1,7 +1,5 @@ -// @flow - -import { NewApplicationFormWrapper } from 'NewApplication' -import { safeFromJsonString } from 'utilities' +import { NewApplicationFormWrapper } from 'NewApplication/components/NewApplicationForm' +import { safeFromJsonString } from 'utilities/json-utils' import type { Buyer, Product } from 'NewApplication/types' import type { FieldDefinition } from 'Types' @@ -19,10 +17,10 @@ document.addEventListener('DOMContentLoaded', () => { const { buyersPath, productsPath, - createServicePlanPath, - createApplicationPath, - createApplicationPlanPath, - serviceSubscriptionsPath + createServicePlanPath = '', + createApplicationPath = '', + createApplicationPlanPath = '', + serviceSubscriptionsPath = '' } = dataset const product = safeFromJsonString(dataset.product) const products = safeFromJsonString(dataset.mostRecentlyUpdatedProducts) @@ -32,8 +30,8 @@ document.addEventListener('DOMContentLoaded', () => { const buyers = safeFromJsonString(dataset.mostRecentlyCreatedBuyers) const buyersCount = safeFromJsonString(dataset.buyersCount) const definedFields = safeFromJsonString(dataset.definedFields) - const validationErrors = safeFromJsonString(dataset.errors) || {} - const error: string | void = validationErrors.hasOwnProperty('base') ? validationErrors.base[0] : undefined + const validationErrors = safeFromJsonString<{ base?: string[] }>(dataset.errors) ?? { base: [] } + const error: string | undefined = validationErrors.base?.[0] NewApplicationFormWrapper({ createApplicationPath, diff --git a/app/javascript/packs/new_mapping_rule.js b/app/javascript/packs/new_mapping_rule.js deleted file mode 100644 index f229c7aaf7..0000000000 --- a/app/javascript/packs/new_mapping_rule.js +++ /dev/null @@ -1,25 +0,0 @@ -// @flow - -import { NewMappingRuleWrapper } from 'MappingRules' -import { safeFromJsonString } from 'utilities' - -const CONTAINER_ID = 'new-mapping-rule-form' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById(CONTAINER_ID) - - if (!container) { - return - } - - const { url, httpMethods, topLevelMetrics, methods, isProxyProEnabled, errors } = container.dataset - - NewMappingRuleWrapper({ - url, - topLevelMetrics: safeFromJsonString(topLevelMetrics) || [], - methods: safeFromJsonString(methods) || [], - isProxyProEnabled: isProxyProEnabled !== undefined, - httpMethods: safeFromJsonString>(httpMethods) || [], - errors: safeFromJsonString(errors) - }, CONTAINER_ID) -}) diff --git a/app/javascript/packs/new_mapping_rule.ts b/app/javascript/packs/new_mapping_rule.ts new file mode 100644 index 0000000000..cad41213d9 --- /dev/null +++ b/app/javascript/packs/new_mapping_rule.ts @@ -0,0 +1,23 @@ +import { NewMappingRuleWrapper } from 'MappingRules/components/NewMappingRule' +import { safeFromJsonString } from 'utilities/json-utils' + +const CONTAINER_ID = 'new-mapping-rule-form' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(CONTAINER_ID) + + if (!container) { + throw new Error('The target ID was not found: ' + CONTAINER_ID) + } + + const { url = '', httpMethods, topLevelMetrics, methods, isProxyProEnabled, errors } = container.dataset + + NewMappingRuleWrapper({ + url, + topLevelMetrics: safeFromJsonString(topLevelMetrics) ?? [], + methods: safeFromJsonString(methods) ?? [], + isProxyProEnabled: isProxyProEnabled !== undefined, + httpMethods: safeFromJsonString(httpMethods) ?? [], + errors: safeFromJsonString(errors) + }, CONTAINER_ID) +}) diff --git a/app/javascript/packs/new_service.js b/app/javascript/packs/new_service.js deleted file mode 100644 index d1be7c6aad..0000000000 --- a/app/javascript/packs/new_service.js +++ /dev/null @@ -1,9 +0,0 @@ -import { NewServiceFormWrapper } from 'NewService' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const newServiceWrapper = document.getElementById('new_service_wrapper') - const newServiceFormProps = safeFromJsonString(newServiceWrapper.dataset.newServiceData) - - NewServiceFormWrapper(newServiceFormProps, 'new_service_wrapper') -}) diff --git a/app/javascript/packs/new_service.ts b/app/javascript/packs/new_service.ts new file mode 100644 index 0000000000..a8453fb5eb --- /dev/null +++ b/app/javascript/packs/new_service.ts @@ -0,0 +1,18 @@ +import { NewServiceFormWrapper } from 'NewService/components/NewServiceForm' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'NewService/components/NewServiceForm' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'new_service_wrapper' + const newServiceWrapper = document.getElementById(containerId) + + if (!newServiceWrapper) { + throw new Error('The target ID was not found: ' + containerId) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME + const newServiceFormProps = safeFromJsonString(newServiceWrapper.dataset.newServiceData)! + + NewServiceFormWrapper(newServiceFormProps, containerId) +}) diff --git a/app/javascript/packs/permissions.js b/app/javascript/packs/permissions.js deleted file mode 100644 index 6668a19d5b..0000000000 --- a/app/javascript/packs/permissions.js +++ /dev/null @@ -1,17 +0,0 @@ -import 'core-js/es7/array' - -import React from 'react' -import { render } from 'react-dom' - -import { PermissionsForm } from 'Users/components/PermissionsForm' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById('user-permissions-form') - - const initialState = safeFromJsonString(container.dataset.state) - const services = safeFromJsonString(container.dataset.services) - const features = safeFromJsonString(container.dataset.features) - - render(, container) -}) diff --git a/app/javascript/packs/permissions.ts b/app/javascript/packs/permissions.ts new file mode 100644 index 0000000000..4abcbc8339 --- /dev/null +++ b/app/javascript/packs/permissions.ts @@ -0,0 +1,19 @@ +import { PermissionsFormWrapper } from 'Users/components/PermissionsForm' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'Users/components/PermissionsForm' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'user-permissions-form' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const initialState = safeFromJsonString(container.dataset.state) + const services = safeFromJsonString(container.dataset.services) ?? [] + const features = safeFromJsonString(container.dataset.features) ?? [] + + PermissionsFormWrapper({ features, initialState, services }, containerId) +}) diff --git a/app/javascript/packs/plans-metrics.js b/app/javascript/packs/plans_metrics.ts similarity index 64% rename from app/javascript/packs/plans-metrics.js rename to app/javascript/packs/plans_metrics.ts index ca792327b9..6019f0e60e 100644 --- a/app/javascript/packs/plans-metrics.js +++ b/app/javascript/packs/plans_metrics.ts @@ -1,16 +1,16 @@ -import { safeFromJsonString } from 'utilities' +import { safeFromJsonString } from 'utilities/json-utils' document.addEventListener('DOMContentLoaded', () => { - function toggleMetricVisibility (id) { + function toggleMetricVisibility (id: string) { document.getElementById(`metric_${id}`) - .classList + ?.classList .toggle('hidden') } - document.querySelectorAll('th.backend_api_metric_title') + document.querySelectorAll('th.backend_api_metric_title') .forEach(th => { const { collapsible, metrics } = th.dataset - const ids = safeFromJsonString(metrics) + const ids = safeFromJsonString(metrics) ?? [] if (collapsible) { th.classList.add('collapsible') @@ -23,7 +23,8 @@ document.addEventListener('DOMContentLoaded', () => { const caret = document.createElement('i') caret.classList.add('fa', 'fa-caret-down') - const span = th.querySelector('span') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME + const span = th.querySelector('span')! span.insertBefore(caret, span.firstChild) span.addEventListener('click', toggleBackendAPI) diff --git a/app/javascript/packs/plans_table.js b/app/javascript/packs/plans_table.js deleted file mode 100644 index 3867d23193..0000000000 --- a/app/javascript/packs/plans_table.js +++ /dev/null @@ -1,28 +0,0 @@ -// @flow - -import { PlansTableCardWrapper } from 'Plans/components/PlansTableCard' -import { safeFromJsonString } from 'utilities' - -import type { Plan } from 'Types' - -document.addEventListener('DOMContentLoaded', () => { - const containerId = 'plans_table' - const container = document.getElementById(containerId) - - if (!container) { - return - } - - const { dataset } = container - const { searchHref } = dataset - const columns = safeFromJsonString>(dataset.columns) || [] - const count = safeFromJsonString(dataset.count) || 0 - const plans = safeFromJsonString(dataset.plans) || [] - - PlansTableCardWrapper({ - columns, - plans, - count, - searchHref - }, containerId) -}) diff --git a/app/javascript/packs/plans_table.ts b/app/javascript/packs/plans_table.ts new file mode 100644 index 0000000000..36d782aa73 --- /dev/null +++ b/app/javascript/packs/plans_table.ts @@ -0,0 +1,26 @@ +import { PlansTableCardWrapper } from 'Plans/components/PlansTableCard' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'Plans/components/PlansTableCard' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'plans_table' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { dataset } = container + const { searchHref = '' } = dataset + const columns = safeFromJsonString(dataset.columns) ?? [] + const count = safeFromJsonString(dataset.count) ?? 0 + const plans = safeFromJsonString(dataset.plans) ?? [] + + PlansTableCardWrapper({ + columns, + plans, + count, + searchHref + }, containerId) +}) diff --git a/app/javascript/packs/policies.js b/app/javascript/packs/policies.ts similarity index 73% rename from app/javascript/packs/policies.js rename to app/javascript/packs/policies.ts index ce53603cdf..8289f14ea4 100644 --- a/app/javascript/packs/policies.js +++ b/app/javascript/packs/policies.ts @@ -1,5 +1,4 @@ -// @flow - +/* eslint-disable @typescript-eslint/no-unsafe-assignment -- FIXME */ import { PoliciesWrapper as PoliciesWidget } from 'Policies' document.addEventListener('DOMContentLoaded', () => { @@ -9,7 +8,7 @@ document.addEventListener('DOMContentLoaded', () => { throw new Error('Policies Widget needs a valid DOM Element to render') } - const { registry, chain, serviceId } = policiesContainer.dataset + const { registry = '', chain = '', serviceId = '' } = policiesContainer.dataset PoliciesWidget({ registry: JSON.parse(registry), diff --git a/app/javascript/packs/product_metrics_index.js b/app/javascript/packs/product_metrics_index.ts similarity index 68% rename from app/javascript/packs/product_metrics_index.js rename to app/javascript/packs/product_metrics_index.ts index 9e0c305e37..72af3405d5 100644 --- a/app/javascript/packs/product_metrics_index.js +++ b/app/javascript/packs/product_metrics_index.ts @@ -1,6 +1,4 @@ -// @flow - -import { ProductIndexPageWrapper } from 'Metrics' +import { ProductIndexPageWrapper } from 'Metrics/components/ProductIndexPage' import { safeFromJsonString } from 'utilities/json-utils' import type { Metric } from 'Types' @@ -15,9 +13,9 @@ document.addEventListener('DOMContentLoaded', () => { } const { dataset } = container - const { applicationPlansPath, addMappingRulePath, createMetricPath, mappingRulesPath } = dataset - const metrics = safeFromJsonString>(dataset.metrics) || [] - const metricsCount = safeFromJsonString(dataset.metricsCount) || metrics.length + const { applicationPlansPath = '', addMappingRulePath = '', createMetricPath = '', mappingRulesPath = '' } = dataset + const metrics = safeFromJsonString(dataset.metrics) ?? [] + const metricsCount = safeFromJsonString(dataset.metricsCount) ?? metrics.length ProductIndexPageWrapper({ applicationPlansPath, diff --git a/app/javascript/packs/products_index.js b/app/javascript/packs/products_index.js deleted file mode 100644 index 0f3274d50c..0000000000 --- a/app/javascript/packs/products_index.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow - -import { ProductsIndexPageWrapper } from 'Products' -import { safeFromJsonString } from 'utilities' - -import type { Product } from 'Products/types' - -const containerId = 'products' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById(containerId) - - if (!container) { - return - } - - const { newProductPath, products, productsCount } = container.dataset - - ProductsIndexPageWrapper({ - newProductPath, - products: safeFromJsonString(products) || [], - productsCount: safeFromJsonString(productsCount) || 0 - }, containerId) -}) diff --git a/app/javascript/packs/products_index.ts b/app/javascript/packs/products_index.ts new file mode 100644 index 0000000000..aa415d73d2 --- /dev/null +++ b/app/javascript/packs/products_index.ts @@ -0,0 +1,22 @@ +import { ProductsIndexPageWrapper } from 'Products/components/IndexPage' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Product } from 'Products/types' + +const containerId = 'products' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { newProductPath = '', products, productsCount } = container.dataset + + ProductsIndexPageWrapper({ + newProductPath, + products: safeFromJsonString(products) ?? [], + productsCount: safeFromJsonString(productsCount) ?? 0 + }, containerId) +}) diff --git a/app/javascript/packs/products_used_list.js b/app/javascript/packs/products_used_list.js deleted file mode 100644 index 81ffaab20a..0000000000 --- a/app/javascript/packs/products_used_list.js +++ /dev/null @@ -1,22 +0,0 @@ -// @flow - -import { ProductsUsedListCardWrapper } from 'BackendApis' -import { safeFromJsonString } from 'utilities' - -import type { CompactListItem } from 'Common' - -const containerId = 'products-used-list-container' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById(containerId) - - if (!container) { - return - } - - const { products } = container.dataset - - ProductsUsedListCardWrapper({ - products: safeFromJsonString>(products) || [] - }, containerId) -}) diff --git a/app/javascript/packs/products_used_list.ts b/app/javascript/packs/products_used_list.ts new file mode 100644 index 0000000000..710083121b --- /dev/null +++ b/app/javascript/packs/products_used_list.ts @@ -0,0 +1,20 @@ +import { ProductsUsedListCardWrapper } from 'BackendApis/components/ProductsUsedListCard' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { CompactListItem } from 'Common/components/CompactListCard' + +const containerId = 'products-used-list-container' + +document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { products } = container.dataset + + ProductsUsedListCardWrapper({ + products: safeFromJsonString(products) ?? [] + }, containerId) +}) diff --git a/app/javascript/packs/providerStats.js b/app/javascript/packs/provider_stats.ts similarity index 99% rename from app/javascript/packs/providerStats.js rename to app/javascript/packs/provider_stats.ts index 1937b2b958..7e77b61fe2 100644 --- a/app/javascript/packs/providerStats.js +++ b/app/javascript/packs/provider_stats.ts @@ -1,10 +1,11 @@ +import $ from 'jquery' + import { statsUsage } from 'Stats/provider/stats_usage' import { statsDaysOfWeek } from 'Stats/provider/stats_days_of_week' import { statsHoursOfDay } from 'Stats/provider/stats_hours_of_day' import { statsTopApps } from 'Stats/provider/stats_top_apps' import { statsApplication } from 'Stats/provider/stats_application' import { statsResponseCodes } from 'Stats/provider/stats_response_codes' -import $ from 'jquery' document.addEventListener('DOMContentLoaded', () => { window.$ = $ diff --git a/app/javascript/packs/quickstarts/container.js b/app/javascript/packs/quickstarts/container.ts similarity index 74% rename from app/javascript/packs/quickstarts/container.js rename to app/javascript/packs/quickstarts/container.ts index 8f35b37fdc..c6fbe158d3 100644 --- a/app/javascript/packs/quickstarts/container.js +++ b/app/javascript/packs/quickstarts/container.ts @@ -1,5 +1,3 @@ -// @flow - import { QuickStartContainerWrapper as QuickStartContainer } from 'QuickStarts/components/QuickStartContainer' import { getActiveQuickstart } from 'QuickStarts/utils/progressTracker' import { safeFromJsonString } from 'utilities/json-utils' @@ -14,7 +12,7 @@ document.addEventListener('DOMContentLoaded', () => { const { links, renderCatalog } = container.dataset const parsedRenderCatalog = safeFromJsonString(renderCatalog) - const willRenderQuickStartContainer = getActiveQuickstart() || parsedRenderCatalog + const willRenderQuickStartContainer = getActiveQuickstart() ?? parsedRenderCatalog if (!willRenderQuickStartContainer) { container.remove() @@ -22,13 +20,14 @@ document.addEventListener('DOMContentLoaded', () => { } QuickStartContainer({ - links: safeFromJsonString>(links) || [], + links: safeFromJsonString<[string, string, string][]>(links) ?? [], renderCatalog: parsedRenderCatalog }, containerId) const wrapperContainer = document.getElementById('wrapper') const quickStartsContainer = document.querySelector('.pfext-quick-start-drawer__body') - // $FlowIgnore HACK of the year: We need QuickStartContainer to wrap the whole #wrapper for the Drawer to work properly. - quickStartsContainer.after(wrapperContainer) + if (quickStartsContainer && wrapperContainer) { + quickStartsContainer.after(wrapperContainer) + } }) diff --git a/app/javascript/packs/request_password_page.ts b/app/javascript/packs/request_password_page.ts new file mode 100644 index 0000000000..d451f04e49 --- /dev/null +++ b/app/javascript/packs/request_password_page.ts @@ -0,0 +1,17 @@ +import { RequestPasswordWrapper as RequestPassword } from 'LoginPage/RequestPasswordWrapper' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'LoginPage/RequestPasswordWrapper' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'pf-request-page-container' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME + const requestPageProps = safeFromJsonString(container.dataset.requestProps)! + RequestPassword(requestPageProps, containerId) +}) diff --git a/app/javascript/packs/service_active_docs.js b/app/javascript/packs/service_active_docs.js deleted file mode 100644 index d2523003e3..0000000000 --- a/app/javascript/packs/service_active_docs.js +++ /dev/null @@ -1,18 +0,0 @@ -import SwaggerUI from 'swagger-ui' -import { autocompleteOAS3 } from './OAS3Autocomplete' -import 'swagger-ui/dist/swagger-ui.css' - -document.addEventListener('DOMContentLoaded', () => { - const containerId = 'swagger-ui-container' - const DATA_URL = 'p/admin/api_docs/account_data.json' - const { url, baseUrl, serviceEndpoint } = document.getElementById(containerId).dataset - const accountDataUrl = `${baseUrl}${DATA_URL}` - - const responseInterceptor = (response) => autocompleteOAS3(response, accountDataUrl, serviceEndpoint) - - SwaggerUI({ - url, - dom_id: `#${containerId}`, - responseInterceptor - }) -}) diff --git a/app/javascript/packs/service_active_docs.ts b/app/javascript/packs/service_active_docs.ts new file mode 100644 index 0000000000..7857418414 --- /dev/null +++ b/app/javascript/packs/service_active_docs.ts @@ -0,0 +1,26 @@ +import SwaggerUI from 'swagger-ui' +import 'swagger-ui/dist/swagger-ui.css' + +import { autocompleteOAS3 } from 'ActiveDocs/OAS3Autocomplete' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'swagger-ui-container' + const DATA_URL = 'p/admin/api_docs/account_data.json' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + const { url, baseUrl, serviceEndpoint = '' } = container.dataset + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- FIXME + const accountDataUrl = `${baseUrl}${DATA_URL}` + + const responseInterceptor: SwaggerUI.SwaggerUIOptions['responseInterceptor'] = (response) => autocompleteOAS3(response, accountDataUrl, serviceEndpoint) + + SwaggerUI({ + url, + // eslint-disable-next-line @typescript-eslint/naming-convention -- SwaggerUI API + dom_id: `#${containerId}`, + responseInterceptor + }) +}) diff --git a/app/javascript/packs/services.js b/app/javascript/packs/services.ts similarity index 100% rename from app/javascript/packs/services.js rename to app/javascript/packs/services.ts diff --git a/app/javascript/packs/settings.js b/app/javascript/packs/settings.ts similarity index 100% rename from app/javascript/packs/settings.js rename to app/javascript/packs/settings.ts diff --git a/app/javascript/packs/settingsPageStyles.js b/app/javascript/packs/settingsPageStyles.js deleted file mode 100644 index 76e6321fa1..0000000000 --- a/app/javascript/packs/settingsPageStyles.js +++ /dev/null @@ -1 +0,0 @@ -import 'patternflyStyles/settingsPage' diff --git a/app/javascript/packs/settings_page_styles.ts b/app/javascript/packs/settings_page_styles.ts new file mode 100644 index 0000000000..f40874bdf3 --- /dev/null +++ b/app/javascript/packs/settings_page_styles.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/no-unresolved -- TODO: remove this pack +import 'patternflyStyles/settingsPage' diff --git a/app/javascript/packs/sign_up_page.ts b/app/javascript/packs/sign_up_page.ts new file mode 100644 index 0000000000..93f4c831e4 --- /dev/null +++ b/app/javascript/packs/sign_up_page.ts @@ -0,0 +1,22 @@ +import { SignupPageWrapper } from 'LoginPage/SignupPageWrapper' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'LoginPage/SignupPageWrapper' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'pf-login-page-container' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const oldLoginWrapper = document.getElementById('old-login-page-wrapper') + if (oldLoginWrapper?.parentNode) { + oldLoginWrapper.parentNode.removeChild(oldLoginWrapper) + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME + const signupPageProps = safeFromJsonString(container.dataset.signupProps)! + SignupPageWrapper(signupPageProps, 'pf-login-page-container') +}) diff --git a/app/javascript/packs/stats.js b/app/javascript/packs/stats.ts similarity index 99% rename from app/javascript/packs/stats.js rename to app/javascript/packs/stats.ts index b8a94ba927..461b9728a1 100644 --- a/app/javascript/packs/stats.js +++ b/app/javascript/packs/stats.ts @@ -1,5 +1,6 @@ -import { statsApplication } from 'Stats/buyer' import $ from 'jquery' +import { statsApplication } from 'Stats/buyer' + window.$ = $ window.Stats = { statsApplication } diff --git a/app/javascript/packs/stripe_form.ts b/app/javascript/packs/stripe_form.ts new file mode 100644 index 0000000000..a81fcb0256 --- /dev/null +++ b/app/javascript/packs/stripe_form.ts @@ -0,0 +1,24 @@ +import { StripeFormWrapper } from 'PaymentGateways/stripe/components/StripeFormWrapper' +import { safeFromJsonString } from 'utilities/json-utils' + +import type { Props } from 'PaymentGateways/stripe/components/StripeFormWrapper' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'stripe-form-wrapper' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const containerDataset = container.dataset + + StripeFormWrapper({ + stripePublishableKey: containerDataset.stripePublishableKey ?? '', + setupIntentSecret: containerDataset.setupIntentSecret ?? '', + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- FIXME: we can assume it's there, but that doesn't make it right + billingAddressDetails: safeFromJsonString(containerDataset.billingAddress)!, + successUrl: containerDataset.successUrl ?? '', + isCreditCardStored: containerDataset.creditCardStored === 'true' + }, containerId) +}) diff --git a/app/javascript/packs/system_name_input_popover.js b/app/javascript/packs/system_name_input_popover.ts similarity index 61% rename from app/javascript/packs/system_name_input_popover.js rename to app/javascript/packs/system_name_input_popover.ts index 39102f478a..a26ef2c839 100644 --- a/app/javascript/packs/system_name_input_popover.js +++ b/app/javascript/packs/system_name_input_popover.ts @@ -1,13 +1,11 @@ -// @flow - -import { SystemNamePopoverWrapper } from 'Common' +import { SystemNamePopoverWrapper } from 'Common/components/SystemNamePopover' document.addEventListener('DOMContentLoaded', function () { const containerId = 'system_name_popover' const container = document.getElementById(containerId) if (!container) { - return + throw new Error('The target ID was not found: ' + containerId) } SystemNamePopoverWrapper(container) diff --git a/app/javascript/packs/validateSignup.js b/app/javascript/packs/validate_signup.ts similarity index 62% rename from app/javascript/packs/validateSignup.js rename to app/javascript/packs/validate_signup.ts index e2aae81fa9..39163234a2 100644 --- a/app/javascript/packs/validateSignup.js +++ b/app/javascript/packs/validate_signup.ts @@ -1,17 +1,14 @@ -// @flow - import validate from 'validate.js' document.addEventListener('DOMContentLoaded', () => { - // $FlowFixMe[incompatible-type] should be safe to assume it is HTMLFormElement - const form: HTMLFormElement = document.getElementById('signup_form') - // $FlowFixMe[incompatible-type] should be safe to assume it is HTMLInputElement - const submitBtn: HTMLInputElement = document.querySelector('input[type="submit"]') - // $FlowFixMe[incompatible-type] should be safe to assume it is HTMLInputElement - const captchaInput: HTMLInputElement = document.getElementById('captchaChecked') + const form = document.getElementById('signup_form') as HTMLFormElement + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style -- Need to cast to HTMLButtonElement + const submitBtn = document.querySelector('input[type="submit"]') as HTMLButtonElement + const captchaInput = document.getElementById('captchaChecked') as HTMLInputElement // Fields 'org_name', 'username' and 'email' are always required const mandatoryFields = { + // eslint-disable-next-line @typescript-eslint/naming-convention 'account[org_name]': { presence: true, length: { minimum: 1 } @@ -25,27 +22,28 @@ document.addEventListener('DOMContentLoaded', () => { email: true, length: { minimum: 1 } } - } + } as const // Fields 'password' and 'password_confirmation' are optional (can be disabled) const isPasswordRequired = document.querySelectorAll('input[type="password"]').length > 0 - const passwordFields = isPasswordRequired ? { + const passwordFields = isPasswordRequired && { 'account[user][password]': { presence: true, length: { minimum: 1 } }, + // eslint-disable-next-line @typescript-eslint/naming-convention 'account[user][password_confirmation]': { presence: true, equality: 'account[user][password]' } - } : null + } const captchaRequired: boolean = document.querySelector('.g-recaptcha') !== null - const captchaFields = captchaRequired ? { + const captchaFields = captchaRequired && { 'captchaChecked': { presence: true, length: { minimum: 1 } } - } : null + } const constraints = Object.assign({}, mandatoryFields, passwordFields, captchaFields) @@ -53,8 +51,9 @@ document.addEventListener('DOMContentLoaded', () => { captchaInput.value = captchaRequired ? '' : 'ok' const inputs = document.querySelectorAll('input') - inputs.forEach(input => input.addEventListener('keyup', (event: KeyboardEvent) => { - const errors = validate(form, constraints) - submitBtn.disabled = !!errors - })) + inputs.forEach(input => { + input.addEventListener('keyup', () => { + submitBtn.disabled = Boolean(validate(form, constraints)) + }) + }) }) diff --git a/app/javascript/packs/vertical_nav.js b/app/javascript/packs/vertical_nav.js deleted file mode 100644 index 384b83dadf..0000000000 --- a/app/javascript/packs/vertical_nav.js +++ /dev/null @@ -1,22 +0,0 @@ -// @flow - -import { VerticalNavWrapper as VerticalNav } from 'Navigation/components/VerticalNav' -import { safeFromJsonString } from 'utilities' - -document.addEventListener('DOMContentLoaded', () => { - const container = document.getElementById('vertical-nav-wrapper') - - if (!container) { - return - } - - const { activeItem, activeSection, currentApi, sections } = container.dataset - - VerticalNav({ - sections: safeFromJsonString(sections) || [], - activeSection, - activeItem, - currentApi: safeFromJsonString(currentApi) }, - 'vertical-nav-wrapper' - ) -}) diff --git a/app/javascript/packs/vertical_nav.ts b/app/javascript/packs/vertical_nav.ts new file mode 100644 index 0000000000..b95ea92062 --- /dev/null +++ b/app/javascript/packs/vertical_nav.ts @@ -0,0 +1,20 @@ +import { VerticalNavWrapper as VerticalNav } from 'Navigation/components/VerticalNav' +import { safeFromJsonString } from 'utilities/json-utils' + +document.addEventListener('DOMContentLoaded', () => { + const containerId = 'vertical-nav-wrapper' + const container = document.getElementById(containerId) + + if (!container) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { activeItem, activeSection, currentApi, sections } = container.dataset + + VerticalNav({ + sections: safeFromJsonString(sections) ?? [], + activeSection, + activeItem, + currentApi: safeFromJsonString(currentApi) + }, containerId) +}) diff --git a/app/javascript/packs/wizard_backend_api.js b/app/javascript/packs/wizard_backend_api.ts similarity index 52% rename from app/javascript/packs/wizard_backend_api.js rename to app/javascript/packs/wizard_backend_api.ts index 3c98bac873..e248cc5dd9 100644 --- a/app/javascript/packs/wizard_backend_api.js +++ b/app/javascript/packs/wizard_backend_api.ts @@ -1,9 +1,15 @@ document.addEventListener('DOMContentLoaded', () => { - const useExampleLink = document.getElementById('use-example-api') - const { url } = useExampleLink.dataset + const containerId = 'use-example-api' + const useExampleLink = document.getElementById(containerId) - const nameInput = document.getElementById('backend_api_name') - const urlInput = document.getElementById('backend_api_private_endpoint') + if (!useExampleLink) { + throw new Error('The target ID was not found: ' + containerId) + } + + const { url = '' } = useExampleLink.dataset + + const nameInput = document.getElementById('backend_api_name') as HTMLInputElement + const urlInput = document.getElementById('backend_api_private_endpoint') as HTMLInputElement useExampleLink.addEventListener('click', e => { if (!nameInput.value) { diff --git a/app/javascript/src/ActiveDocs/OAS3Autocomplete.ts b/app/javascript/src/ActiveDocs/OAS3Autocomplete.ts new file mode 100644 index 0000000000..b4ac082aaa --- /dev/null +++ b/app/javascript/src/ActiveDocs/OAS3Autocomplete.ts @@ -0,0 +1,122 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-condition */ +/* eslint-disable @typescript-eslint/default-param-last */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/naming-convention */ +/* TODO: this module needs to be properly typed !!! */ + +import { fetchData } from 'utilities/fetchData' + +import type { Response as SwaggerUIResponse } from 'swagger-ui' +import type { AccountData } from 'Types/SwaggerTypes' + +const X_DATA_ATTRIBUTE = 'x-data-threescale-name' + +const X_DATA_PARAMS_DESCRIPTIONS = { + user_keys: 'First user key from latest 5 applications', + app_ids: 'Latest 5 applications (across all accounts and services)', + app_keys: 'First application key from the latest five applications' +} as const + +const addAutocompleteToParam = (param: any, accountData: AccountData): any => { + const xDataKey = param[X_DATA_ATTRIBUTE] as keyof typeof X_DATA_PARAMS_DESCRIPTIONS + const autocompleteData = accountData[xDataKey] + const paramHasAutocompleteData = autocompleteData && autocompleteData.length > 0 && + autocompleteData.every(p => p.name !== '') + + return paramHasAutocompleteData + ? { + ...param, + examples: autocompleteData.reduce<{ summary: string; value: string }[]>((examples, item) => ( + [...examples, { summary: item.name, value: item.value }] + ), [{ summary: X_DATA_PARAMS_DESCRIPTIONS[xDataKey], value: '-' }]) + } + : param +} + +const injectParametersToPathOperation = (pathOperation: any, accountData: AccountData): any => { + const operationParameters = pathOperation.parameters + if (!operationParameters) return pathOperation + const parametersWithAutocompleteData = operationParameters.map((param: any) => X_DATA_ATTRIBUTE in param ? addAutocompleteToParam(param, accountData) : param) + return { + ...pathOperation, + parameters: parametersWithAutocompleteData + } +} + +const injectAutocompleteToCommonParameters = (parameters: any[], accountData: AccountData): any[] => parameters.map( + param => X_DATA_ATTRIBUTE in param ? addAutocompleteToParam(param, accountData) : param +) + +const injectParametersToPath = ( + path: Record, + commonParameters: any[] | null | undefined = [], + accountData: AccountData +): any => (Object.keys(path).reduce>((updatedPath, item) => { + updatedPath[item] = (item === 'parameters' && commonParameters) + ? injectAutocompleteToCommonParameters(commonParameters, accountData) + : injectParametersToPathOperation(path[item], accountData) + return updatedPath +}, {})) + +const injectAutocompleteToResponseBody = (responseBody: string | { paths?: Record }, accountData: AccountData): any | string => { + const res = (typeof responseBody !== 'string' && responseBody.paths && accountData) ? { + ...responseBody, + paths: Object.keys(responseBody.paths).reduce>((paths, path) => { + const commonParameters = responseBody.paths![path].parameters + paths[path] = injectParametersToPath(responseBody.paths![path], commonParameters, accountData) + return paths + }, {}) + } : responseBody + return res +} + +const injectServerToResponseBody = (responseBody: any | string, serviceEndpoint: string): any | string => { + if (typeof responseBody === 'string') { + return responseBody + } + + const originalServers = responseBody.servers || [] + const servers = serviceEndpoint ? [{ url: serviceEndpoint }] : originalServers + + return { + ...responseBody, + servers + } +} + +export interface Response extends SwaggerUIResponse { + body: { + servers: unknown; + paths: any; + }; + data: string; + text: string; +} + +export const autocompleteOAS3 = async (response: SwaggerUIResponse, accountDataUrl: string, serviceEndpoint: string): Promise => { + const bodyWithServer = injectServerToResponseBody(response.body, serviceEndpoint) + const data = await fetchData<{ results: AccountData }>(accountDataUrl) + + let body = undefined + try { + body = data.results + ? injectAutocompleteToResponseBody(bodyWithServer, data.results) + : bodyWithServer + } catch (error: unknown) { + console.error(error) + body = bodyWithServer + } + + return { + ...response, + body, + data: JSON.stringify(body), + text: JSON.stringify(body) + } +} diff --git a/app/javascript/src/BackendApis/components/AddBackendForm.jsx b/app/javascript/src/BackendApis/components/AddBackendForm.tsx similarity index 50% rename from app/javascript/src/BackendApis/components/AddBackendForm.jsx rename to app/javascript/src/BackendApis/components/AddBackendForm.tsx index c506e5a565..0a87ba404d 100644 --- a/app/javascript/src/BackendApis/components/AddBackendForm.jsx +++ b/app/javascript/src/BackendApis/components/AddBackendForm.tsx @@ -1,34 +1,43 @@ -// @flow - -import * as React from 'react' import { useState } from 'react' - import { - Form, ActionGroup, Button, + Form, PageSection, PageSectionVariants } from '@patternfly/react-core' -import { BackendSelect, PathInput, NewBackendModal } from 'BackendApis' -import { CSRFToken, createReactWrapper, notice } from 'utilities' +import { CSRFToken } from 'utilities/CSRFToken' +import { createReactWrapper } from 'utilities/createReactWrapper' +import { notice } from 'utilities/flash' +import { BackendSelect } from 'BackendApis/components/BackendSelect' +import { PathInput } from 'BackendApis/components/PathInput' +import { NewBackendModal } from 'BackendApis/components/NewBackendModal' + +import type { FunctionComponent } from 'react' import type { Backend } from 'Types' import './AddBackendForm.scss' -type Props = { - backend: Backend | null, - backends: Backend[], - url: string, - inlineErrors: null | { - backend_api_id?: Array, - path?: Array - }, - backendsPath: string +interface Props { + backend: Backend | null; + backends: Backend[]; + url: string; + inlineErrors: { + // eslint-disable-next-line @typescript-eslint/naming-convention -- Comes from rails like that + backend_api_id?: string[]; + path?: string[]; + } | null; + backendsPath: string; } -const AddBackendForm = ({ backend: initialBackend, backends, url, backendsPath, inlineErrors }: Props): React.Node => { +const AddBackendForm: FunctionComponent = ({ + backend: initialBackend, + backends, + url, + backendsPath, + inlineErrors +}) => { const [backend, setBackend] = useState(initialBackend) const [updatedBackends, setUpdatedBackends] = useState(backends) const [path, setPath] = useState('') @@ -37,48 +46,48 @@ const AddBackendForm = ({ backend: initialBackend, backends, url, backendsPath, const isFormComplete = backend !== null - const handleOnCreateBackend = (backend: Backend) => { + const handleOnCreateBackend = (newBackend: Backend) => { notice('Backend created') setIsModalOpen(false) - setBackend(backend) - setUpdatedBackends([backend, ...updatedBackends]) + setBackend(newBackend) + setUpdatedBackends([newBackend, ...updatedBackends]) } return ( <>
setLoading(true)} + id="new_backend_api_config" + method="post" + onSubmit={() => { setLoading(true) }} // isWidthLimited TODO: use when available instead of hardcoded css > - + setIsModalOpen(true)} + error={inlineErrors?.backend_api_id?.[0]} searchPlaceholder="Find a backend" - error={inlineErrors ? inlineErrors.backend_api_id && inlineErrors.backend_api_id[0] : undefined} + onCreateNewBackend={() => { setIsModalOpen(true) }} + onSelect={setBackend} /> @@ -88,14 +97,15 @@ const AddBackendForm = ({ backend: initialBackend, backends, url, backendsPath, setIsModalOpen(false)} isOpen={isModalOpen} + onClose={() => { setIsModalOpen(false) }} onCreateBackend={handleOnCreateBackend} /> ) } -const AddBackendFormWrapper = (props: Props, containerId: string): void => createReactWrapper(, containerId) +// eslint-disable-next-line react/jsx-props-no-spreading +const AddBackendFormWrapper = (props: Props, containerId: string): void => { createReactWrapper(, containerId) } -export { AddBackendForm, AddBackendFormWrapper } +export { AddBackendForm, AddBackendFormWrapper, Props } diff --git a/app/javascript/src/BackendApis/components/BackendSelect.jsx b/app/javascript/src/BackendApis/components/BackendSelect.tsx similarity index 62% rename from app/javascript/src/BackendApis/components/BackendSelect.jsx rename to app/javascript/src/BackendApis/components/BackendSelect.tsx index 5bcbbbcf9b..5156fff3ce 100644 --- a/app/javascript/src/BackendApis/components/BackendSelect.jsx +++ b/app/javascript/src/BackendApis/components/BackendSelect.tsx @@ -1,26 +1,31 @@ -// @flow - -import * as React from 'react' - import { Button } from '@patternfly/react-core' import { PlusCircleIcon } from '@patternfly/react-icons' -import { SelectWithModal } from 'Common' +import { SelectWithModal } from 'Common/components/SelectWithModal' + +import type { Props as SelectWithModalProps } from 'Common/components/SelectWithModal' import type { Backend } from 'Types' import './BackendSelect.scss' -type Props = { - backend: Backend | null, - backends: Backend[], - onCreateNewBackend: () => void, - error?: string, - searchPlaceholder?: string, - onSelect: (Backend | null) => void +interface Props { + backend: Backend | null; + backends: Backend[]; + onCreateNewBackend: () => void; + error?: string; + searchPlaceholder?: string; + onSelect: (backend: Backend | null) => void; } -const BackendSelect = ({ backend, backends, onSelect, onCreateNewBackend, searchPlaceholder, error }: Props): React.Node => { - const cells = [ +const BackendSelect: React.FunctionComponent = ({ + backend, + backends, + onSelect, + onCreateNewBackend, + searchPlaceholder, + error +}) => { + const cells: SelectWithModalProps['cells'] = [ { title: 'Name', propName: 'name' }, { title: 'Private Base URL', propName: 'privateEndpoint' }, { title: 'Last updated', propName: 'updatedAt' } @@ -28,36 +33,34 @@ const BackendSelect = ({ backend, backends, onSelect, onCreateNewBackend, search return ( <> - {/* $FlowFixMe[prop-missing] Implement async pagination */} { throw new Error('Function not implemented.') }} // FIXME: add it or make it optional + footerLabel="View all backends" + header="Recently created backends" + helperTextInvalid={error} id="backend_api_config_backend_api_id" - name="backend_api_config[backend_api_id]" - // $FlowIssue[incompatible-type] backend is compatible with null item={backend} items={backends.map(b => ({ ...b, description: b.privateEndpoint }))} itemsCount={backends.length} - cells={cells} - // $FlowIssue[incompatible-type] It should not complain since Record.id has union "number | string" - onSelect={onSelect} - header="Recently created backends" - title="Select a backend" + label="Backend" + name="backend_api_config[backend_api_id]" placeholder="Select a backend" - footerLabel="View all backends" searchPlaceholder={searchPlaceholder} - helperTextInvalid={error} + title="Select a backend" + onSelect={onSelect} /> ) } -export { BackendSelect } + +export { BackendSelect, Props } diff --git a/app/javascript/src/BackendApis/components/DescriptionInput.jsx b/app/javascript/src/BackendApis/components/DescriptionInput.jsx deleted file mode 100644 index 78d9d8f155..0000000000 --- a/app/javascript/src/BackendApis/components/DescriptionInput.jsx +++ /dev/null @@ -1,27 +0,0 @@ -// @flow - -import * as React from 'react' - -import { FormGroup, TextArea } from '@patternfly/react-core' - -type Props = { - description: string, - setDescription: string => void -} - -const DescriptionInput = ({ description, setDescription }: Props): React.Node => ( - - - { !!errors.description &&

{errors.description}

} - - - ) -} -export { ServiceManualListItems } diff --git a/app/javascript/src/NewService/components/FormElements/ServiceManualListItems.tsx b/app/javascript/src/NewService/components/FormElements/ServiceManualListItems.tsx new file mode 100644 index 0000000000..e07e0ab9d6 --- /dev/null +++ b/app/javascript/src/NewService/components/FormElements/ServiceManualListItems.tsx @@ -0,0 +1,53 @@ +/* eslint-disable @typescript-eslint/no-unnecessary-condition -- FIXME: check if errors should be optional */ +import { useState } from 'react' + +import { Label } from 'NewService/components/FormElements/Label' + +import type { FunctionComponent, ChangeEvent, SetStateAction } from 'react' +import type { ServiceFormTemplate } from 'NewService/types' + +type Props = ServiceFormTemplate + +const ServiceManualListItems: FunctionComponent = ({ + service, + errors +}) => { + const [name, setName] = useState(service.name) + const [systemName, setSystemName] = useState(service.system_name) + const [description, setDescription] = useState(service.description) + const onChange = (fn: (cb: SetStateAction) => void) => (e: ChangeEvent) => { fn(e.currentTarget.value) } + + return ( + <> +
  • +
  • +
  • +
  • +
  • +