diff --git a/.betterer.results b/.betterer.results index c4690e9daf2..8f1d4f3aa93 100644 --- a/.betterer.results +++ b/.betterer.results @@ -956,6 +956,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "18"], [0, 0, 0, "Unexpected any. Specify a different type.", "19"] ], + "packages/grafana-ui/src/components/Splitter/Splitter.tsx:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], "packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], diff --git a/devenv/docker/blocks/auth/jwt_proxy/cloak.sql b/devenv/docker/blocks/auth/jwt_proxy/cloak.sql index 653caaa1e22..ec1c6f005a5 100644 --- a/devenv/docker/blocks/auth/jwt_proxy/cloak.sql +++ b/devenv/docker/blocks/auth/jwt_proxy/cloak.sql @@ -2,8 +2,8 @@ -- PostgreSQL database dump -- --- Dumped from database version 12.2 (Debian 12.2-2.pgdg100+1) --- Dumped by pg_dump version 12.2 (Debian 12.2-2.pgdg100+1) +-- Dumped from database version 16.1 +-- Dumped by pg_dump version 16.1 SET statement_timeout = 0; SET lock_timeout = 0; @@ -386,7 +386,7 @@ CREATE TABLE public.component_config ( id character varying(36) NOT NULL, component_id character varying(36) NOT NULL, name character varying(255) NOT NULL, - value character varying(4000) + value text ); @@ -488,7 +488,8 @@ CREATE TABLE public.event_entity ( session_id character varying(255), event_time bigint, type character varying(255), - user_id character varying(255) + user_id character varying(255), + details_json_long_value text ); @@ -1097,7 +1098,7 @@ ALTER TABLE public.resource_scope OWNER TO keycloak; CREATE TABLE public.resource_server ( id character varying(36) NOT NULL, allow_rs_remote_mgmt boolean DEFAULT false NOT NULL, - policy_enforce_mode character varying(15) NOT NULL, + policy_enforce_mode smallint NOT NULL, decision_strategy smallint DEFAULT 1 NOT NULL ); @@ -1132,8 +1133,8 @@ CREATE TABLE public.resource_server_policy ( name character varying(255) NOT NULL, description character varying(255), type character varying(255) NOT NULL, - decision_strategy character varying(20), - logic character varying(20), + decision_strategy smallint, + logic smallint, resource_server_id character varying(36) NOT NULL, owner character varying(255) ); @@ -1484,7 +1485,6 @@ bfbcc1e9-f129-4336-a0cd-b6960a811bd9 \N direct-grant-validate-password master 5f 5a2470c4-3136-4cf0-8383-e74a413ccd48 \N direct-grant-validate-otp master 99865746-4232-46f0-84b5-20952fe9eb51 0 20 f \N \N 47c96943-ad68-4d93-afff-ff54fc86eb0b \N registration-page-form master 1695e7d2-ad80-4502-8479-8121a6e2a2f0 0 10 t 8fb96669-d28d-4173-a8f4-dc24d41c7d27 \N a6678624-1bd4-4793-bfac-68551cf0ac7c \N registration-user-creation master 8fb96669-d28d-4173-a8f4-dc24d41c7d27 0 20 f \N \N -5b45827d-5dfd-4152-a99e-373cb975ef87 \N registration-profile-action master 8fb96669-d28d-4173-a8f4-dc24d41c7d27 0 40 f \N \N 5a2fb70d-63ae-4604-b37c-ae043d6a900d \N registration-password-action master 8fb96669-d28d-4173-a8f4-dc24d41c7d27 0 50 f \N \N 0b06a30e-daa7-498a-9fdb-899abbf36450 \N registration-recaptcha-action master 8fb96669-d28d-4173-a8f4-dc24d41c7d27 3 60 f \N \N b6ab0b5d-8184-4609-bb81-da8413dfb858 \N reset-credentials-choose-user master 954b046d-2b24-405e-84ee-c44ffe603df2 0 10 f \N \N @@ -1511,11 +1511,6 @@ d600bb67-e258-44be-8f69-f1bae9c35a0f \N idp-username-password-form master ca3a36 90cc39a9-cddb-49bd-b9f5-d64d03341333 \N auth-otp-form master a7d23655-efbb-4950-8ab6-50dbc85681a0 0 20 f \N \N b0634301-594e-42db-9736-6c90ebbeb8b2 \N http-basic-authenticator master 57c56583-d91c-4399-bd15-05a1a17d48c1 0 10 f \N \N 34fa4d44-716b-4b2a-b98e-aa9748154292 \N docker-http-basic-authenticator master 032b05cf-0007-44da-a370-b42039f6b762 0 10 f \N \N -4838277a-46ea-4d95-bd86-d8dc6fdce352 \N no-cookie-redirect master 1c7af06b-3085-46c3-849c-34c67f581b9e 0 10 f \N \N -59a349ee-20ce-42d8-b20b-8f902c09742d \N \N master 1c7af06b-3085-46c3-849c-34c67f581b9e 0 20 t 85c00992-77dd-4262-8744-a9dd8521e98e \N -d9b5fa46-6595-4406-9841-2c0720dbf644 \N basic-auth master 85c00992-77dd-4262-8744-a9dd8521e98e 0 10 f \N \N -3a4ee6f1-1528-47c7-aeda-f317248b3b93 \N basic-auth-otp master 85c00992-77dd-4262-8744-a9dd8521e98e 3 20 f \N \N -014847fc-06df-4ddf-a8f2-deeb0f1eb59a \N auth-spnego master 85c00992-77dd-4262-8744-a9dd8521e98e 3 30 f \N \N b46bc4f6-2fe5-44d5-b47f-36880742cf50 \N auth-cookie grafana a38aeb47-f27e-4e68-82ff-7cc7371a47a7 2 10 f \N \N 6cec48cc-066a-4e3e-8158-85351bfa4c27 \N auth-spnego grafana a38aeb47-f27e-4e68-82ff-7cc7371a47a7 3 20 f \N \N 63c55c5a-ad11-4f83-9d6e-d8ca2efcaf66 \N identity-provider-redirector grafana a38aeb47-f27e-4e68-82ff-7cc7371a47a7 2 25 f \N \N @@ -1530,7 +1525,6 @@ b46bc4f6-2fe5-44d5-b47f-36880742cf50 \N auth-cookie grafana a38aeb47-f27e-4e68-8 d87abeef-9f1d-46f5-9f36-acd7eaf21a72 \N direct-grant-validate-otp grafana b3491338-0630-4232-97e7-a518c254b248 0 20 f \N \N 4f204bab-0311-44b4-80b6-37d23fd0fd5a \N registration-page-form grafana 9d02badd-cb1c-4655-bf5e-f888861433ff 0 10 t c3ed2ad1-cfb4-49fa-8c75-cf5047527c68 \N 2d4ee446-623c-42a0-8d4a-9f6c4f7f28ec \N registration-user-creation grafana c3ed2ad1-cfb4-49fa-8c75-cf5047527c68 0 20 f \N \N -d806effc-dd17-4468-9a98-4e1c2f9e799d \N registration-profile-action grafana c3ed2ad1-cfb4-49fa-8c75-cf5047527c68 0 40 f \N \N 306fa749-c191-43c6-bf04-0eb6d3d02732 \N registration-password-action grafana c3ed2ad1-cfb4-49fa-8c75-cf5047527c68 0 50 f \N \N 7de9bbee-eb3d-4f3e-a134-e7e8d4a6df25 \N registration-recaptcha-action grafana c3ed2ad1-cfb4-49fa-8c75-cf5047527c68 3 60 f \N \N 8a31d18e-1622-4eac-8eff-9434fa9cade3 \N reset-credentials-choose-user grafana 3085fb68-fc1f-4e1c-a8be-33fb45194b04 0 10 f \N \N @@ -1557,11 +1551,6 @@ b8ce6905-73eb-493b-9ce1-408ec55e3c46 \N conditional-user-configured grafana 21fb 54d7692d-c0e3-40ef-9ef9-d9e8227d618d \N auth-otp-form grafana 21fbd70a-286f-431a-abc4-fbf6590fcdc3 0 20 f \N \N 3722f24d-6ffb-4b20-a481-1fd8a17afdf6 \N http-basic-authenticator grafana ba53abf5-9a64-4371-810b-67378eb3d781 0 10 f \N \N a700b05f-a61d-4eeb-ad75-1a3df05ed429 \N docker-http-basic-authenticator grafana 95e02703-f5bc-4e04-8bef-f6adc2d8173f 0 10 f \N \N -035c4f94-03a6-4101-a729-f3c01ee4c490 \N no-cookie-redirect grafana f397495e-d073-4ef1-babf-569a338db596 0 10 f \N \N -29f310db-b302-44b2-9182-4b91648cbabf \N \N grafana f397495e-d073-4ef1-babf-569a338db596 0 20 t 56c40f89-4d69-46fd-bb18-d6c01808d2af \N -4e7d257c-e013-4597-a44d-b186a85606af \N basic-auth grafana 56c40f89-4d69-46fd-bb18-d6c01808d2af 0 10 f \N \N -2ba05817-a59f-4e72-a565-f3b4591390dc \N basic-auth-otp grafana 56c40f89-4d69-46fd-bb18-d6c01808d2af 3 20 f \N \N -5db9c781-6718-4674-a833-9a4ac3e8212e \N auth-spnego grafana 56c40f89-4d69-46fd-bb18-d6c01808d2af 3 30 f \N \N 5f032dbb-bd37-425b-af1e-ba555c7a8245 \N \N grafana b478ecfb-db7e-4797-a245-8fc3b4dec884 1 30 t b3491338-0630-4232-97e7-a518c254b248 \N \. @@ -1589,8 +1578,6 @@ ca3a3600-552c-4849-9a9d-826c8aa3e646 Verify Existing Account by Re-authenticatio a7d23655-efbb-4950-8ab6-50dbc85681a0 First broker login - Conditional OTP Flow to determine if the OTP is required for the authentication master basic-flow f t 57c56583-d91c-4399-bd15-05a1a17d48c1 saml ecp SAML ECP Profile Authentication Flow master basic-flow t t 032b05cf-0007-44da-a370-b42039f6b762 docker auth Used by Docker clients to authenticate against the IDP master basic-flow t t -1c7af06b-3085-46c3-849c-34c67f581b9e http challenge An authentication flow based on challenge-response HTTP Authentication Schemes master basic-flow t t -85c00992-77dd-4262-8744-a9dd8521e98e Authentication Options Authentication options. master basic-flow f t a38aeb47-f27e-4e68-82ff-7cc7371a47a7 browser browser based authentication grafana basic-flow t t c53e357f-e276-43aa-b36c-46366a7ffd35 forms Username, password, otp and other auth forms. grafana basic-flow f t cf4831e9-3e1d-452e-984e-e6d4d9eeafb5 Browser - Conditional OTP Flow to determine if the OTP is required for the authentication grafana basic-flow f t @@ -1609,8 +1596,6 @@ df86516c-dcb1-41a8-877e-eb8805bcac8c User creation or linking Flow for the exist 21fbd70a-286f-431a-abc4-fbf6590fcdc3 First broker login - Conditional OTP Flow to determine if the OTP is required for the authentication grafana basic-flow f t ba53abf5-9a64-4371-810b-67378eb3d781 saml ecp SAML ECP Profile Authentication Flow grafana basic-flow t t 95e02703-f5bc-4e04-8bef-f6adc2d8173f docker auth Used by Docker clients to authenticate against the IDP grafana basic-flow t t -f397495e-d073-4ef1-babf-569a338db596 http challenge An authentication flow based on challenge-response HTTP Authentication Schemes grafana basic-flow t t -56c40f89-4d69-46fd-bb18-d6c01808d2af Authentication Options Authentication options. grafana basic-flow f t \. @@ -1840,6 +1825,7 @@ d30340a8-630b-416e-8c93-3ccf932d34f3 false display.on.consent.screen d30340a8-630b-416e-8c93-3ccf932d34f3 false include.in.token.scope a96603aa-e6db-4b3e-8baa-679c75ccfc8f false display.on.consent.screen a96603aa-e6db-4b3e-8baa-679c75ccfc8f false include.in.token.scope +c61f5b19-c17e-49a1-91b8-a0296411b928 gui.order \. @@ -1979,6 +1965,7 @@ a8698f4f-5fa1-4baa-be05-87d03052af49 c61f5b19-c17e-49a1-91b8-a0296411b928 f 169f1dea-80f0-4a99-8509-9abb70ab0a5c a5bb3a5f-fd26-4be6-9557-26e20a03d33d f 169f1dea-80f0-4a99-8509-9abb70ab0a5c d6ffe9fc-a03c-4496-85dc-dbb5e7754587 f 169f1dea-80f0-4a99-8509-9abb70ab0a5c c61f5b19-c17e-49a1-91b8-a0296411b928 f +09b79548-8426-4c0e-8e0b-7488467532c7 c61f5b19-c17e-49a1-91b8-a0296411b928 t \. @@ -2086,6 +2073,7 @@ d47557df-07ff-4cae-bedd-b584c0697852 f95566ed-b955-4668-88fc-e7413fd98615 allowe 2ae4acc4-c6d6-4d2f-92c6-3a222a7d078a 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types oidc-sha256-pairwise-sub-mapper 880a35e4-65a1-4697-836d-fbc46641d676 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types oidc-full-name-mapper b087e631-754f-4c03-8cfc-354c7e7456fe 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types oidc-usermodel-property-mapper +258b8704-0587-4208-996f-96627992e370 80af2f23-4a51-498a-a011-732cf9cfa8f8 priority 100 079e63d4-0862-4e63-a62f-1a168cbbc25c 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types saml-user-property-mapper da61fbc2-7533-4bc1-b0c4-357db9f108e4 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types oidc-address-mapper 37a4be58-26b0-4d4a-9c41-a89b27fc25f6 28d2466c-5af6-4786-a8a2-c25d6cb4833f allowed-protocol-mapper-types saml-user-attribute-mapper @@ -2112,7 +2100,6 @@ bb8c28ca-bb74-4a07-82c3-8293354517be 9877acf2-e1cc-4038-a3c2-75db29b432e0 secret 64ea89c8-a2ce-4d2d-896d-aa49e7ca9fcc 9877acf2-e1cc-4038-a3c2-75db29b432e0 kid 7d80efc5-222b-4b6d-9b99-c3b516a59733 bec1483f-75e7-46e8-916c-102db4cbefb5 80af2f23-4a51-498a-a011-732cf9cfa8f8 certificate MIICnTCCAYUCBgF+u1ir8jANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdncmFmYW5hMB4XDTIyMDIwMjE2NDkxN1oXDTMyMDIwMjE2NTA1N1owEjEQMA4GA1UEAwwHZ3JhZmFuYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKg5kB303DkDs5jSW1b7b7kvKfxIJorHD+7wPz2TcisfTu7rchrqAJiR/HtsPICyAw1h5ef8fGgCJf/k0z00osl/COvK8iHUdvGUnubuKUXaVwlbyaTnnyjSMUAkx+67OCrkY9B2drtZrtVc+fwnggqCsCkpoXg97tcUyfPlcUJnanxsYbirZ5KH+/e+x1jlsuBiwxascmB4IoT/zJknk5l1IVXmSOiDgqhzKRfHhVlRijOlfKyCn/EDtiv7wyQTP9wvd97zGPJqkkF2yNxueMftJsgGkF6+CZMY71BioOWAt2V8OwI32b/1v30DhtBmKdoUNGpEeCjSk91zzZqTFZUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEABlW64QxuREB81VMGsyhj4Q5RykFaVuD5O8YlwUpmVfAVLzb0Drf54Kn4bnpnckKyYV+T+HsN4QXt81UE41xH0Aai2H3vrGH+PJf6aLPCDE+jpMqtN3n6IgImJXJPL8upMfhhWDv4nkM4uynEwWupzmrKi4oJuTETSMktJby4o6//XWnCzCVMoAGFJU4gtjBUzOMLW26zD+yc+BuUtfR3HzItVHSZKQSNSFO0kVS68RgrER8qJw07z3BOJ2bPpPM0PYyEngGMaowz/T6lI32ymGMWYMAnslthS1KAW9xcTBwnrW1nMhe5a0LPxIktys/wJtxIHZLc5sOddGT4xYklLg== 48e8b904-1393-43a4-aaa1-30e2d9634b36 80af2f23-4a51-498a-a011-732cf9cfa8f8 privateKey MIIEowIBAAKCAQEAqDmQHfTcOQOzmNJbVvtvuS8p/EgmiscP7vA/PZNyKx9O7utyGuoAmJH8e2w8gLIDDWHl5/x8aAIl/+TTPTSiyX8I68ryIdR28ZSe5u4pRdpXCVvJpOefKNIxQCTH7rs4KuRj0HZ2u1mu1Vz5/CeCCoKwKSmheD3u1xTJ8+VxQmdqfGxhuKtnkof7977HWOWy4GLDFqxyYHgihP/MmSeTmXUhVeZI6IOCqHMpF8eFWVGKM6V8rIKf8QO2K/vDJBM/3C933vMY8mqSQXbI3G54x+0myAaQXr4JkxjvUGKg5YC3ZXw7AjfZv/W/fQOG0GYp2hQ0akR4KNKT3XPNmpMVlQIDAQABAoIBAF3kEt3FZoyj1j97WOOJXmf7PPHDy081n1z61jEl9FjBFqse2gbPiBmfkU3JsVMbB70WYN1D/KOIX3EdZBELKbhQoMgJ826SSPi4vJ+jWYHVRTLB+h+B70E3X6mvXa+O6uB1rIgTNl2Gxp/rTtM/scLwAiZXR/n2hzGgNr9b1gT7D7kyCUIKDiJsQed2pA6ZbSDNTQQDE2qeN/Rr/+VV4XRuIIdBXn+Brap8ihjx4Gnn/SDBKM3MZoacwgS+9CZNhLjs8Ou4xD+KyitbbGGY4ZK/ZW2eSAH4ra8vVGTDK6bJrMTAE/73A23Evp/sKtRkFqcNumJ3rCykcAJorDUK48ECgYEA0TpkTwK6f2a72ncmw7Xzy4zdu+FdkI9PzWmS4IrbYOYRwsRMQLowsUPIdtU0EMrs7PRl1dSQa3/kAnw5J8wogkqVf4dJ3/lb/N5qtsjHP87N35QMXnMdE/BC6o7t5e+iRoHMloAuSBonGC9uBn1UeHWrNeLCB8+upJoSEBKbEQ0CgYEAzdSoKL4CJo31gVEqoJFPzPemsYGmV6Zl1Vj8mqMbQd8wcJoSJWbNV/3sfpIqdvOJOXQrzm+LYIbhhUnS3ZlGBmFsqUtC7dw3AqLg53msCyJLxmCIib0m/ONCY9qczV4OkUM6HVAdgzmMqqhk5ZB70IdUyStn2meqXKXLGFlLJKkCgYEAuizHTTcUVIFJ7x/PMp8ZjKqQM7pZ02Rykkm7FGr6wsJ2U2TwpTgIU/QI0RTt+3NWV5MxepBm4gEvFrcK9MrJ0QYk+RGdPttYay5Ors8B3Vlb//Jw/ypXWYKVSLpeHhiZwTuGnPT6OdZrqy2pLcUgAQBTlONt3B2FPZqLMBoeOZECgYBuCwm0bpF7x13AO4LMwaOmc6jdMfGa3s2G2MKEcjt6ZjbhnJ2i/Wk/Z/RuXvrxCZcN7nwVLDGZ88LSnftsmiuD8cZEZIZt4NRQRoBzgOtoMHfOoYGeElCr11yBQjme2nBzXTvOvCxrIfOAsfLvgOWRQSklPF2TuOSuD72bUPIJsQKBgBbeb8rIXKRRFC3A0IkKm8C51gG8mMgPdxZMKKuVhpb6D8B5aPh+WW44yNOpn7LInYI4jzf3Kv+kcj0PNH3nFaplnyCGFfmUIg27SAsRcrJcTlXtIKooZw6oPU+dQfAo11suArVAVD6OQc/7z99VoIpLN0cUHfS/g0H1dx/r/32o -258b8704-0587-4208-996f-96627992e370 80af2f23-4a51-498a-a011-732cf9cfa8f8 priority 100 12cd94c5-bd7e-4a5c-95e2-256b0bcf14bd 261e38de-3e1f-40a3-9200-f5aac1975701 allowed-protocol-mapper-types oidc-address-mapper f33b34f1-3793-4786-a281-b286fce52f45 261e38de-3e1f-40a3-9200-f5aac1975701 allowed-protocol-mapper-types saml-role-list-mapper d056c1de-9aa1-46a0-a644-fafb33088967 261e38de-3e1f-40a3-9200-f5aac1975701 allowed-protocol-mapper-types saml-user-property-mapper @@ -2226,11 +2213,11 @@ b4c89bc8-3945-4963-80b5-3da62e8c54ad 18a7066b-fe71-410e-9581-69f78347ec29 -- COPY public.credential (id, salt, type, user_id, created_date, user_label, secret_data, credential_data, priority) FROM stdin; -d4b2c483-1dd3-47f6-86bf-42548009918d \N password 74e29604-ff35-42bb-a26d-4d0b81ef0917 1643820449817 \N {"value":"Hou7HlbGvohOx6II0VSCP4BIGI4Cyzy+BcXbPUQe/kaMQzNU77kH2pOKZ236UPfkiCyOLe7A3oS0afExA+ymAQ==","salt":"urXvCw0KdWf9s74km4G+lA==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 cb2bd4ed-94b8-4259-bcaa-9250c3fb28d3 \N password 6db3c5e5-b84b-4f9d-a7a8-8d05b03c929d 1657026827644 \N {"value":"q3Z59Nh/5bdezDEpCwEbMPu8d+VgJ5WetafXkR8l0FlsTTkSDQgW+j6GaM3seJR93p3/jCxyfsvZl062d1pq7w==","salt":"ohuHnjLnwF9dBZ38DRJJWg==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 -b58e1964-6466-40b2-879c-982b724d7f9c \N password 88692d07-bb9a-46cf-844c-7ff5c529cd04 1657026904515 \N {"value":"+/0zWjiJyE3+dCOEf0SO6G3n1/LsFAVoDAZREKTfN4vQ5xJH8srJoCjxcgb+bI1crMr8gknDlFyGRy7CpYn2VQ==","salt":"v/2okNt3wGOZz+x4DjOCDQ==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 -3ff7dd8f-a299-4b51-bf5d-99665ccfd313 \N password 8f58cbec-6e40-4bab-bff0-1c5ff899fe2e 1657026943075 \N {"value":"nMYodMJMiq/J8g9vRPktGc7WSWnOKr6leMDZX4p9K9KgAUYeXFDSu+d29PWWn0rFn93dL0PNdIdHWNQhfkIDMg==","salt":"rmi9WLHgarmIXGukecSIig==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 c9582964-cfdd-49a1-99fb-847604b0c78c \N password 1a85b7e0-4baa-420b-89f8-1cea43a540dd 1662480997923 \N {"value":"ViNTHbpBUNdtH1qGSlip7WFI8Z9lvcGQdbL8Yw48zUgB46jVFbD1eNrOw68p3ovDwfDCIJKm34EFNbw9/uzHSg==","salt":"Z9P8RfnrQwCn0xUTpWC2DQ==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 +b58e1964-6466-40b2-879c-982b724d7f9c \N password 88692d07-bb9a-46cf-844c-7ff5c529cd04 1657026904515 \N {"value":"L/GNO2HAU90A/ajXqyZyujncf+GfJiLWzNVTIDAVj1k=","salt":"L6WsIapZ+hKo0809G6c6SA==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 +d4b2c483-1dd3-47f6-86bf-42548009918d \N password 74e29604-ff35-42bb-a26d-4d0b81ef0917 1643820449817 \N {"value":"GweNaTEq3+hCqr5bBhnfqUd0oAiv8G4eUBkQUqtqiTI=","salt":"z64RYF8zRJz9ko0KDrIPxw==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 +3ff7dd8f-a299-4b51-bf5d-99665ccfd313 \N password 8f58cbec-6e40-4bab-bff0-1c5ff899fe2e 1657026943075 \N {"value":"81KWe14rtsbn3SS6YbWzBy2SvBQhmH+0MDHkK7aXCbo=","salt":"CnzQUkkAMD1tPk1KFDDm1w==","additionalParameters":{}} {"hashIterations":27500,"algorithm":"pbkdf2-sha256","additionalParameters":{}} 10 \. @@ -2239,118 +2226,125 @@ c9582964-cfdd-49a1-99fb-847604b0c78c \N password 1a85b7e0-4baa-420b-89f8-1cea43a -- COPY public.databasechangelog (id, author, filename, dateexecuted, orderexecuted, exectype, md5sum, description, comments, tag, liquibase, contexts, labels, deployment_id) FROM stdin; -authn-3.4.0.CR1-refresh-token-max-reuse glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.706593 49 EXECUTED \N addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 -1.0.0.Final-KEYCLOAK-5461 sthorger@redhat.com META-INF/jpa-changelog-1.0.0.Final.xml 2022-02-02 16:47:26.017844 1 EXECUTED \N createTable tableName=APPLICATION_DEFAULT_ROLES; createTable tableName=CLIENT; createTable tableName=CLIENT_SESSION; createTable tableName=CLIENT_SESSION_ROLE; createTable tableName=COMPOSITE_ROLE; createTable tableName=CREDENTIAL; createTable tab... \N 3.5.4 \N \N 3820445829 -1.0.0.Final-KEYCLOAK-5461 sthorger@redhat.com META-INF/db2-jpa-changelog-1.0.0.Final.xml 2022-02-02 16:47:26.03122 2 MARK_RAN \N createTable tableName=APPLICATION_DEFAULT_ROLES; createTable tableName=CLIENT; createTable tableName=CLIENT_SESSION; createTable tableName=CLIENT_SESSION_ROLE; createTable tableName=COMPOSITE_ROLE; createTable tableName=CREDENTIAL; createTable tab... \N 3.5.4 \N \N 3820445829 -1.1.0.Beta1 sthorger@redhat.com META-INF/jpa-changelog-1.1.0.Beta1.xml 2022-02-02 16:47:26.06085 3 EXECUTED \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=CLIENT_ATTRIBUTES; createTable tableName=CLIENT_SESSION_NOTE; createTable tableName=APP_NODE_REGISTRATIONS; addColumn table... \N 3.5.4 \N \N 3820445829 -1.1.0.Final sthorger@redhat.com META-INF/jpa-changelog-1.1.0.Final.xml 2022-02-02 16:47:26.065284 4 EXECUTED \N renameColumn newColumnName=EVENT_TIME, oldColumnName=TIME, tableName=EVENT_ENTITY \N 3.5.4 \N \N 3820445829 -4.8.0-KEYCLOAK-8835 sguilhen@redhat.com META-INF/jpa-changelog-4.8.0.xml 2022-02-02 16:47:26.928034 70 EXECUTED \N addNotNullConstraint columnName=SSO_MAX_LIFESPAN_REMEMBER_ME, tableName=REALM; addNotNullConstraint columnName=SSO_IDLE_TIMEOUT_REMEMBER_ME, tableName=REALM \N 3.5.4 \N \N 3820445829 -1.2.0.Beta1 psilva@redhat.com META-INF/jpa-changelog-1.2.0.Beta1.xml 2022-02-02 16:47:26.130908 5 EXECUTED \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=PROTOCOL_MAPPER; createTable tableName=PROTOCOL_MAPPER_CONFIG; createTable tableName=... \N 3.5.4 \N \N 3820445829 -1.2.0.Beta1 psilva@redhat.com META-INF/db2-jpa-changelog-1.2.0.Beta1.xml 2022-02-02 16:47:26.133863 6 MARK_RAN \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=PROTOCOL_MAPPER; createTable tableName=PROTOCOL_MAPPER_CONFIG; createTable tableName=... \N 3.5.4 \N \N 3820445829 -1.2.0.RC1 bburke@redhat.com META-INF/jpa-changelog-1.2.0.CR1.xml 2022-02-02 16:47:26.183318 7 EXECUTED \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=MIGRATION_MODEL; createTable tableName=IDENTITY_P... \N 3.5.4 \N \N 3820445829 -1.2.0.RC1 bburke@redhat.com META-INF/db2-jpa-changelog-1.2.0.CR1.xml 2022-02-02 16:47:26.186858 8 MARK_RAN \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=MIGRATION_MODEL; createTable tableName=IDENTITY_P... \N 3.5.4 \N \N 3820445829 -1.2.0.Final keycloak META-INF/jpa-changelog-1.2.0.Final.xml 2022-02-02 16:47:26.19172 9 EXECUTED \N update tableName=CLIENT; update tableName=CLIENT; update tableName=CLIENT \N 3.5.4 \N \N 3820445829 -1.3.0 bburke@redhat.com META-INF/jpa-changelog-1.3.0.xml 2022-02-02 16:47:26.242162 10 EXECUTED \N delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=ADMI... \N 3.5.4 \N \N 3820445829 -1.4.0 bburke@redhat.com META-INF/jpa-changelog-1.4.0.xml 2022-02-02 16:47:26.275929 11 EXECUTED \N delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 -1.4.0 bburke@redhat.com META-INF/db2-jpa-changelog-1.4.0.xml 2022-02-02 16:47:26.278548 12 MARK_RAN \N delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 -1.5.0 bburke@redhat.com META-INF/jpa-changelog-1.5.0.xml 2022-02-02 16:47:26.287616 13 EXECUTED \N delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 -1.6.1_from15 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.299798 14 EXECUTED \N addColumn tableName=REALM; addColumn tableName=KEYCLOAK_ROLE; addColumn tableName=CLIENT; createTable tableName=OFFLINE_USER_SESSION; createTable tableName=OFFLINE_CLIENT_SESSION; addPrimaryKey constraintName=CONSTRAINT_OFFL_US_SES_PK2, tableName=... \N 3.5.4 \N \N 3820445829 -1.6.1_from16-pre mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.302088 15 MARK_RAN \N delete tableName=OFFLINE_CLIENT_SESSION; delete tableName=OFFLINE_USER_SESSION \N 3.5.4 \N \N 3820445829 -1.6.1_from16 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.303889 16 MARK_RAN \N dropPrimaryKey constraintName=CONSTRAINT_OFFLINE_US_SES_PK, tableName=OFFLINE_USER_SESSION; dropPrimaryKey constraintName=CONSTRAINT_OFFLINE_CL_SES_PK, tableName=OFFLINE_CLIENT_SESSION; addColumn tableName=OFFLINE_USER_SESSION; update tableName=OF... \N 3.5.4 \N \N 3820445829 -1.6.1 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.306641 17 EXECUTED \N empty \N 3.5.4 \N \N 3820445829 -1.7.0 bburke@redhat.com META-INF/jpa-changelog-1.7.0.xml 2022-02-02 16:47:26.338791 18 EXECUTED \N createTable tableName=KEYCLOAK_GROUP; createTable tableName=GROUP_ROLE_MAPPING; createTable tableName=GROUP_ATTRIBUTE; createTable tableName=USER_GROUP_MEMBERSHIP; createTable tableName=REALM_DEFAULT_GROUPS; addColumn tableName=IDENTITY_PROVIDER; ... \N 3.5.4 \N \N 3820445829 -1.8.0 mposolda@redhat.com META-INF/jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.381463 19 EXECUTED \N addColumn tableName=IDENTITY_PROVIDER; createTable tableName=CLIENT_TEMPLATE; createTable tableName=CLIENT_TEMPLATE_ATTRIBUTES; createTable tableName=TEMPLATE_SCOPE_MAPPING; dropNotNullConstraint columnName=CLIENT_ID, tableName=PROTOCOL_MAPPER; ad... \N 3.5.4 \N \N 3820445829 -1.8.0-2 keycloak META-INF/jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.390165 20 EXECUTED \N dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; update tableName=CREDENTIAL \N 3.5.4 \N \N 3820445829 -authz-3.4.0.CR1-resource-server-pk-change-part1 glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.679075 45 EXECUTED \N addColumn tableName=RESOURCE_SERVER_POLICY; addColumn tableName=RESOURCE_SERVER_RESOURCE; addColumn tableName=RESOURCE_SERVER_SCOPE \N 3.5.4 \N \N 3820445829 -1.8.0 mposolda@redhat.com META-INF/db2-jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.392862 21 MARK_RAN \N addColumn tableName=IDENTITY_PROVIDER; createTable tableName=CLIENT_TEMPLATE; createTable tableName=CLIENT_TEMPLATE_ATTRIBUTES; createTable tableName=TEMPLATE_SCOPE_MAPPING; dropNotNullConstraint columnName=CLIENT_ID, tableName=PROTOCOL_MAPPER; ad... \N 3.5.4 \N \N 3820445829 -1.8.0-2 keycloak META-INF/db2-jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.395652 22 MARK_RAN \N dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; update tableName=CREDENTIAL \N 3.5.4 \N \N 3820445829 -1.9.0 mposolda@redhat.com META-INF/jpa-changelog-1.9.0.xml 2022-02-02 16:47:26.40969 23 EXECUTED \N update tableName=REALM; update tableName=REALM; update tableName=REALM; update tableName=REALM; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=REALM; update tableName=REALM; customChange; dr... \N 3.5.4 \N \N 3820445829 -1.9.1 keycloak META-INF/jpa-changelog-1.9.1.xml 2022-02-02 16:47:26.414344 24 EXECUTED \N modifyDataType columnName=PRIVATE_KEY, tableName=REALM; modifyDataType columnName=PUBLIC_KEY, tableName=REALM; modifyDataType columnName=CERTIFICATE, tableName=REALM \N 3.5.4 \N \N 3820445829 -1.9.1 keycloak META-INF/db2-jpa-changelog-1.9.1.xml 2022-02-02 16:47:26.416193 25 MARK_RAN \N modifyDataType columnName=PRIVATE_KEY, tableName=REALM; modifyDataType columnName=CERTIFICATE, tableName=REALM \N 3.5.4 \N \N 3820445829 -1.9.2 keycloak META-INF/jpa-changelog-1.9.2.xml 2022-02-02 16:47:26.437367 26 EXECUTED \N createIndex indexName=IDX_USER_EMAIL, tableName=USER_ENTITY; createIndex indexName=IDX_USER_ROLE_MAPPING, tableName=USER_ROLE_MAPPING; createIndex indexName=IDX_USER_GROUP_MAPPING, tableName=USER_GROUP_MEMBERSHIP; createIndex indexName=IDX_USER_CO... \N 3.5.4 \N \N 3820445829 -9.0.1-KEYCLOAK-12579-recreate-constraints keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.981645 84 MARK_RAN \N addUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 -authz-2.0.0 psilva@redhat.com META-INF/jpa-changelog-authz-2.0.0.xml 2022-02-02 16:47:26.481647 27 EXECUTED \N createTable tableName=RESOURCE_SERVER; addPrimaryKey constraintName=CONSTRAINT_FARS, tableName=RESOURCE_SERVER; addUniqueConstraint constraintName=UK_AU8TT6T700S9V50BU18WS5HA6, tableName=RESOURCE_SERVER; createTable tableName=RESOURCE_SERVER_RESOU... \N 3.5.4 \N \N 3820445829 -authz-2.5.1 psilva@redhat.com META-INF/jpa-changelog-authz-2.5.1.xml 2022-02-02 16:47:26.484459 28 EXECUTED \N update tableName=RESOURCE_SERVER_POLICY \N 3.5.4 \N \N 3820445829 -2.1.0-KEYCLOAK-5461 bburke@redhat.com META-INF/jpa-changelog-2.1.0.xml 2022-02-02 16:47:26.523006 29 EXECUTED \N createTable tableName=BROKER_LINK; createTable tableName=FED_USER_ATTRIBUTE; createTable tableName=FED_USER_CONSENT; createTable tableName=FED_USER_CONSENT_ROLE; createTable tableName=FED_USER_CONSENT_PROT_MAPPER; createTable tableName=FED_USER_CR... \N 3.5.4 \N \N 3820445829 -2.2.0 bburke@redhat.com META-INF/jpa-changelog-2.2.0.xml 2022-02-02 16:47:26.532066 30 EXECUTED \N addColumn tableName=ADMIN_EVENT_ENTITY; createTable tableName=CREDENTIAL_ATTRIBUTE; createTable tableName=FED_CREDENTIAL_ATTRIBUTE; modifyDataType columnName=VALUE, tableName=CREDENTIAL; addForeignKeyConstraint baseTableName=FED_CREDENTIAL_ATTRIBU... \N 3.5.4 \N \N 3820445829 -2.3.0 bburke@redhat.com META-INF/jpa-changelog-2.3.0.xml 2022-02-02 16:47:26.541837 31 EXECUTED \N createTable tableName=FEDERATED_USER; addPrimaryKey constraintName=CONSTR_FEDERATED_USER, tableName=FEDERATED_USER; dropDefaultValue columnName=TOTP, tableName=USER_ENTITY; dropColumn columnName=TOTP, tableName=USER_ENTITY; addColumn tableName=IDE... \N 3.5.4 \N \N 3820445829 -2.4.0 bburke@redhat.com META-INF/jpa-changelog-2.4.0.xml 2022-02-02 16:47:26.545809 32 EXECUTED \N customChange \N 3.5.4 \N \N 3820445829 -2.5.0 bburke@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.549823 33 EXECUTED \N customChange; modifyDataType columnName=USER_ID, tableName=OFFLINE_USER_SESSION \N 3.5.4 \N \N 3820445829 -2.5.0-unicode-oracle hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.55176 34 MARK_RAN \N modifyDataType columnName=DESCRIPTION, tableName=AUTHENTICATION_FLOW; modifyDataType columnName=DESCRIPTION, tableName=CLIENT_TEMPLATE; modifyDataType columnName=DESCRIPTION, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=DESCRIPTION,... \N 3.5.4 \N \N 3820445829 -2.5.0-unicode-other-dbs hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.567305 35 EXECUTED \N modifyDataType columnName=DESCRIPTION, tableName=AUTHENTICATION_FLOW; modifyDataType columnName=DESCRIPTION, tableName=CLIENT_TEMPLATE; modifyDataType columnName=DESCRIPTION, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=DESCRIPTION,... \N 3.5.4 \N \N 3820445829 -2.5.0-duplicate-email-support slawomir@dabek.name META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.570727 36 EXECUTED \N addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 -2.5.0-unique-group-names hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.578396 37 EXECUTED \N addUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 -2.5.1 bburke@redhat.com META-INF/jpa-changelog-2.5.1.xml 2022-02-02 16:47:26.581391 38 EXECUTED \N addColumn tableName=FED_USER_CONSENT \N 3.5.4 \N \N 3820445829 -3.0.0 bburke@redhat.com META-INF/jpa-changelog-3.0.0.xml 2022-02-02 16:47:26.584204 39 EXECUTED \N addColumn tableName=IDENTITY_PROVIDER \N 3.5.4 \N \N 3820445829 -3.2.0-fix keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.585877 40 MARK_RAN \N addNotNullConstraint columnName=REALM_ID, tableName=CLIENT_INITIAL_ACCESS \N 3.5.4 \N \N 3820445829 -3.2.0-fix-with-keycloak-5416 keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.587657 41 MARK_RAN \N dropIndex indexName=IDX_CLIENT_INIT_ACC_REALM, tableName=CLIENT_INITIAL_ACCESS; addNotNullConstraint columnName=REALM_ID, tableName=CLIENT_INITIAL_ACCESS; createIndex indexName=IDX_CLIENT_INIT_ACC_REALM, tableName=CLIENT_INITIAL_ACCESS \N 3.5.4 \N \N 3820445829 -3.2.0-fix-offline-sessions hmlnarik META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.591561 42 EXECUTED \N customChange \N 3.5.4 \N \N 3820445829 -3.2.0-fixed keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.669981 43 EXECUTED \N addColumn tableName=REALM; dropPrimaryKey constraintName=CONSTRAINT_OFFL_CL_SES_PK2, tableName=OFFLINE_CLIENT_SESSION; dropColumn columnName=CLIENT_SESSION_ID, tableName=OFFLINE_CLIENT_SESSION; addPrimaryKey constraintName=CONSTRAINT_OFFL_CL_SES_P... \N 3.5.4 \N \N 3820445829 -3.3.0 keycloak META-INF/jpa-changelog-3.3.0.xml 2022-02-02 16:47:26.673701 44 EXECUTED \N addColumn tableName=USER_ENTITY \N 3.5.4 \N \N 3820445829 -authz-3.4.0.CR1-resource-server-pk-change-part2-KEYCLOAK-6095 hmlnarik@redhat.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.681987 46 EXECUTED \N customChange \N 3.5.4 \N \N 3820445829 -authz-3.4.0.CR1-resource-server-pk-change-part3-fixed glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.683661 47 MARK_RAN \N dropIndex indexName=IDX_RES_SERV_POL_RES_SERV, tableName=RESOURCE_SERVER_POLICY; dropIndex indexName=IDX_RES_SRV_RES_RES_SRV, tableName=RESOURCE_SERVER_RESOURCE; dropIndex indexName=IDX_RES_SRV_SCOPE_RES_SRV, tableName=RESOURCE_SERVER_SCOPE \N 3.5.4 \N \N 3820445829 -authz-3.4.0.CR1-resource-server-pk-change-part3-fixed-nodropindex glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.702743 48 EXECUTED \N addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, tableName=RESOURCE_SERVER_POLICY; addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, tableName=RESOURCE_SERVER_RESOURCE; addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, ... \N 3.5.4 \N \N 3820445829 -3.4.0 keycloak META-INF/jpa-changelog-3.4.0.xml 2022-02-02 16:47:26.734467 50 EXECUTED \N addPrimaryKey constraintName=CONSTRAINT_REALM_DEFAULT_ROLES, tableName=REALM_DEFAULT_ROLES; addPrimaryKey constraintName=CONSTRAINT_COMPOSITE_ROLE, tableName=COMPOSITE_ROLE; addPrimaryKey constraintName=CONSTR_REALM_DEFAULT_GROUPS, tableName=REALM... \N 3.5.4 \N \N 3820445829 -3.4.0-KEYCLOAK-5230 hmlnarik@redhat.com META-INF/jpa-changelog-3.4.0.xml 2022-02-02 16:47:26.78037 51 EXECUTED \N createIndex indexName=IDX_FU_ATTRIBUTE, tableName=FED_USER_ATTRIBUTE; createIndex indexName=IDX_FU_CONSENT, tableName=FED_USER_CONSENT; createIndex indexName=IDX_FU_CONSENT_RU, tableName=FED_USER_CONSENT; createIndex indexName=IDX_FU_CREDENTIAL, t... \N 3.5.4 \N \N 3820445829 -3.4.1 psilva@redhat.com META-INF/jpa-changelog-3.4.1.xml 2022-02-02 16:47:26.783989 52 EXECUTED \N modifyDataType columnName=VALUE, tableName=CLIENT_ATTRIBUTES \N 3.5.4 \N \N 3820445829 -3.4.2 keycloak META-INF/jpa-changelog-3.4.2.xml 2022-02-02 16:47:26.786619 53 EXECUTED \N update tableName=REALM \N 3.5.4 \N \N 3820445829 -3.4.2-KEYCLOAK-5172 mkanis@redhat.com META-INF/jpa-changelog-3.4.2.xml 2022-02-02 16:47:26.788788 54 EXECUTED \N update tableName=CLIENT \N 3.5.4 \N \N 3820445829 -4.0.0-KEYCLOAK-6335 bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.794881 55 EXECUTED \N createTable tableName=CLIENT_AUTH_FLOW_BINDINGS; addPrimaryKey constraintName=C_CLI_FLOW_BIND, tableName=CLIENT_AUTH_FLOW_BINDINGS \N 3.5.4 \N \N 3820445829 -4.0.0-CLEANUP-UNUSED-TABLE bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.799493 56 EXECUTED \N dropTable tableName=CLIENT_IDENTITY_PROV_MAPPING \N 3.5.4 \N \N 3820445829 -4.0.0-KEYCLOAK-6228 bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.810686 57 EXECUTED \N dropUniqueConstraint constraintName=UK_JKUWUVD56ONTGSUHOGM8UEWRT, tableName=USER_CONSENT; dropNotNullConstraint columnName=CLIENT_ID, tableName=USER_CONSENT; addColumn tableName=USER_CONSENT; addUniqueConstraint constraintName=UK_JKUWUVD56ONTGSUHO... \N 3.5.4 \N \N 3820445829 -4.0.0-KEYCLOAK-5579-fixed mposolda@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.861332 58 EXECUTED \N dropForeignKeyConstraint baseTableName=CLIENT_TEMPLATE_ATTRIBUTES, constraintName=FK_CL_TEMPL_ATTR_TEMPL; renameTable newTableName=CLIENT_SCOPE_ATTRIBUTES, oldTableName=CLIENT_TEMPLATE_ATTRIBUTES; renameColumn newColumnName=SCOPE_ID, oldColumnName... \N 3.5.4 \N \N 3820445829 -authz-4.0.0.CR1 psilva@redhat.com META-INF/jpa-changelog-authz-4.0.0.CR1.xml 2022-02-02 16:47:26.877018 59 EXECUTED \N createTable tableName=RESOURCE_SERVER_PERM_TICKET; addPrimaryKey constraintName=CONSTRAINT_FAPMT, tableName=RESOURCE_SERVER_PERM_TICKET; addForeignKeyConstraint baseTableName=RESOURCE_SERVER_PERM_TICKET, constraintName=FK_FRSRHO213XCX4WNKOG82SSPMT... \N 3.5.4 \N \N 3820445829 -authz-4.0.0.Beta3 psilva@redhat.com META-INF/jpa-changelog-authz-4.0.0.Beta3.xml 2022-02-02 16:47:26.881203 60 EXECUTED \N addColumn tableName=RESOURCE_SERVER_POLICY; addColumn tableName=RESOURCE_SERVER_PERM_TICKET; addForeignKeyConstraint baseTableName=RESOURCE_SERVER_PERM_TICKET, constraintName=FK_FRSRPO2128CX4WNKOG82SSRFY, referencedTableName=RESOURCE_SERVER_POLICY \N 3.5.4 \N \N 3820445829 -authz-4.2.0.Final mhajas@redhat.com META-INF/jpa-changelog-authz-4.2.0.Final.xml 2022-02-02 16:47:26.886177 61 EXECUTED \N createTable tableName=RESOURCE_URIS; addForeignKeyConstraint baseTableName=RESOURCE_URIS, constraintName=FK_RESOURCE_SERVER_URIS, referencedTableName=RESOURCE_SERVER_RESOURCE; customChange; dropColumn columnName=URI, tableName=RESOURCE_SERVER_RESO... \N 3.5.4 \N \N 3820445829 -authz-4.2.0.Final-KEYCLOAK-9944 hmlnarik@redhat.com META-INF/jpa-changelog-authz-4.2.0.Final.xml 2022-02-02 16:47:26.890482 62 EXECUTED \N addPrimaryKey constraintName=CONSTRAINT_RESOUR_URIS_PK, tableName=RESOURCE_URIS \N 3.5.4 \N \N 3820445829 -4.2.0-KEYCLOAK-6313 wadahiro@gmail.com META-INF/jpa-changelog-4.2.0.xml 2022-02-02 16:47:26.893518 63 EXECUTED \N addColumn tableName=REQUIRED_ACTION_PROVIDER \N 3.5.4 \N \N 3820445829 -4.3.0-KEYCLOAK-7984 wadahiro@gmail.com META-INF/jpa-changelog-4.3.0.xml 2022-02-02 16:47:26.895621 64 EXECUTED \N update tableName=REQUIRED_ACTION_PROVIDER \N 3.5.4 \N \N 3820445829 -4.6.0-KEYCLOAK-7950 psilva@redhat.com META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.89756 65 EXECUTED \N update tableName=RESOURCE_SERVER_RESOURCE \N 3.5.4 \N \N 3820445829 -4.6.0-KEYCLOAK-8377 keycloak META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.908059 66 EXECUTED \N createTable tableName=ROLE_ATTRIBUTE; addPrimaryKey constraintName=CONSTRAINT_ROLE_ATTRIBUTE_PK, tableName=ROLE_ATTRIBUTE; addForeignKeyConstraint baseTableName=ROLE_ATTRIBUTE, constraintName=FK_ROLE_ATTRIBUTE_ID, referencedTableName=KEYCLOAK_ROLE... \N 3.5.4 \N \N 3820445829 -4.6.0-KEYCLOAK-8555 gideonray@gmail.com META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.912693 67 EXECUTED \N createIndex indexName=IDX_COMPONENT_PROVIDER_TYPE, tableName=COMPONENT \N 3.5.4 \N \N 3820445829 -4.7.0-KEYCLOAK-1267 sguilhen@redhat.com META-INF/jpa-changelog-4.7.0.xml 2022-02-02 16:47:26.915771 68 EXECUTED \N addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 -4.7.0-KEYCLOAK-7275 keycloak META-INF/jpa-changelog-4.7.0.xml 2022-02-02 16:47:26.924465 69 EXECUTED \N renameColumn newColumnName=CREATED_ON, oldColumnName=LAST_SESSION_REFRESH, tableName=OFFLINE_USER_SESSION; addNotNullConstraint columnName=CREATED_ON, tableName=OFFLINE_USER_SESSION; addColumn tableName=OFFLINE_USER_SESSION; customChange; createIn... \N 3.5.4 \N \N 3820445829 -authz-7.0.0-KEYCLOAK-10443 psilva@redhat.com META-INF/jpa-changelog-authz-7.0.0.xml 2022-02-02 16:47:26.93061 71 EXECUTED \N addColumn tableName=RESOURCE_SERVER \N 3.5.4 \N \N 3820445829 -8.0.0-adding-credential-columns keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.933771 72 EXECUTED \N addColumn tableName=CREDENTIAL; addColumn tableName=FED_USER_CREDENTIAL \N 3.5.4 \N \N 3820445829 +1.6.1 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.306641 17 EXECUTED 9:d41d8cd98f00b204e9800998ecf8427e empty \N 3.5.4 \N \N 3820445829 +authz-2.5.1 psilva@redhat.com META-INF/jpa-changelog-authz-2.5.1.xml 2022-02-02 16:47:26.484459 28 EXECUTED 9:44bae577f551b3738740281eceb4ea70 update tableName=RESOURCE_SERVER_POLICY \N 3.5.4 \N \N 3820445829 8.0.0-updating-credential-data-not-oracle keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.937673 73 EXECUTED \N update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 3.5.4 \N \N 3820445829 8.0.0-updating-credential-data-oracle keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.939218 74 MARK_RAN \N update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 3.5.4 \N \N 3820445829 -8.0.0-credential-cleanup-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.945819 75 EXECUTED \N dropDefaultValue columnName=COUNTER, tableName=CREDENTIAL; dropDefaultValue columnName=DIGITS, tableName=CREDENTIAL; dropDefaultValue columnName=PERIOD, tableName=CREDENTIAL; dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; dropColumn ... \N 3.5.4 \N \N 3820445829 -8.0.0-resource-tag-support keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.950255 76 EXECUTED \N addColumn tableName=MIGRATION_MODEL; createIndex indexName=IDX_UPDATE_TIME, tableName=MIGRATION_MODEL \N 3.5.4 \N \N 3820445829 -9.0.0-always-display-client keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.955505 77 EXECUTED \N addColumn tableName=CLIENT \N 3.5.4 \N \N 3820445829 -9.0.0-drop-constraints-for-column-increase keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.957216 78 MARK_RAN \N dropUniqueConstraint constraintName=UK_FRSR6T700S9V50BU18WS5PMT, tableName=RESOURCE_SERVER_PERM_TICKET; dropUniqueConstraint constraintName=UK_FRSR6T700S9V50BU18WS5HA6, tableName=RESOURCE_SERVER_RESOURCE; dropPrimaryKey constraintName=CONSTRAINT_O... \N 3.5.4 \N \N 3820445829 -9.0.0-increase-column-size-federated-fk keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.966746 79 EXECUTED \N modifyDataType columnName=CLIENT_ID, tableName=FED_USER_CONSENT; modifyDataType columnName=CLIENT_REALM_CONSTRAINT, tableName=KEYCLOAK_ROLE; modifyDataType columnName=OWNER, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=CLIENT_ID, ta... \N 3.5.4 \N \N 3820445829 -9.0.0-recreate-constraints-after-column-increase keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.969643 80 MARK_RAN \N addNotNullConstraint columnName=CLIENT_ID, tableName=OFFLINE_CLIENT_SESSION; addNotNullConstraint columnName=OWNER, tableName=RESOURCE_SERVER_PERM_TICKET; addNotNullConstraint columnName=REQUESTER, tableName=RESOURCE_SERVER_PERM_TICKET; addNotNull... \N 3.5.4 \N \N 3820445829 -9.0.1-add-index-to-client.client_id keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.975764 81 EXECUTED \N createIndex indexName=IDX_CLIENT_ID, tableName=CLIENT \N 3.5.4 \N \N 3820445829 -9.0.1-KEYCLOAK-12579-drop-constraints keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.977227 82 MARK_RAN \N dropUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 -9.0.1-KEYCLOAK-12579-add-not-null-constraint keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.980058 83 EXECUTED \N addNotNullConstraint columnName=PARENT_GROUP, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 -9.0.1-add-index-to-events keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.985465 85 EXECUTED \N createIndex indexName=IDX_EVENT_TIME, tableName=EVENT_ENTITY \N 3.5.4 \N \N 3820445829 -map-remove-ri keycloak META-INF/jpa-changelog-11.0.0.xml 2022-02-02 16:47:26.98869 86 EXECUTED \N dropForeignKeyConstraint baseTableName=REALM, constraintName=FK_TRAF444KK6QRKMS7N56AIWQ5Y; dropForeignKeyConstraint baseTableName=KEYCLOAK_ROLE, constraintName=FK_KJHO5LE2C0RAL09FL8CM9WFW9 \N 3.5.4 \N \N 3820445829 -map-remove-ri keycloak META-INF/jpa-changelog-12.0.0.xml 2022-02-02 16:47:26.992854 87 EXECUTED \N dropForeignKeyConstraint baseTableName=REALM_DEFAULT_GROUPS, constraintName=FK_DEF_GROUPS_GROUP; dropForeignKeyConstraint baseTableName=REALM_DEFAULT_ROLES, constraintName=FK_H4WPD7W4HSOOLNI3H0SW7BTJE; dropForeignKeyConstraint baseTableName=CLIENT... \N 3.5.4 \N \N 3820445829 -12.1.0-add-realm-localization-table keycloak META-INF/jpa-changelog-12.0.0.xml 2022-02-02 16:47:26.999694 88 EXECUTED \N createTable tableName=REALM_LOCALIZATIONS; addPrimaryKey tableName=REALM_LOCALIZATIONS \N 3.5.4 \N \N 3820445829 -8.0.0-updating-credential-data-not-oracle-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2023-01-09 14:34:23.080082 89 MARK_RAN 8:83f7a671792ca98b3cbd3a1a34862d3d update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 4.8.0 \N \N 3274862955 -8.0.0-updating-credential-data-oracle-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2023-01-09 14:34:23.099857 90 MARK_RAN 8:f58ad148698cf30707a6efbdf8061aa7 update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 4.8.0 \N \N 3274862955 -default-roles keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.144776 91 EXECUTED 8:72d03345fda8e2f17093d08801947773 addColumn tableName=REALM; customChange \N 4.8.0 \N \N 3274862955 -default-roles-cleanup keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.155298 92 EXECUTED 8:61c9233951bd96ffecd9ba75f7d978a4 dropTable tableName=REALM_DEFAULT_ROLES; dropTable tableName=CLIENT_DEFAULT_ROLES \N 4.8.0 \N \N 3274862955 -13.0.0-KEYCLOAK-16844 keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.162911 93 EXECUTED 8:ea82e6ad945cec250af6372767b25525 createIndex indexName=IDX_OFFLINE_USS_PRELOAD, tableName=OFFLINE_USER_SESSION \N 4.8.0 \N \N 3274862955 -map-remove-ri-13.0.0 keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.17617 94 EXECUTED 8:d3f4a33f41d960ddacd7e2ef30d126b3 dropForeignKeyConstraint baseTableName=DEFAULT_CLIENT_SCOPE, constraintName=FK_R_DEF_CLI_SCOPE_SCOPE; dropForeignKeyConstraint baseTableName=CLIENT_SCOPE_CLIENT, constraintName=FK_C_CLI_SCOPE_SCOPE; dropForeignKeyConstraint baseTableName=CLIENT_SC... \N 4.8.0 \N \N 3274862955 -13.0.0-KEYCLOAK-17992-drop-constraints keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.1803 95 MARK_RAN 8:1284a27fbd049d65831cb6fc07c8a783 dropPrimaryKey constraintName=C_CLI_SCOPE_BIND, tableName=CLIENT_SCOPE_CLIENT; dropIndex indexName=IDX_CLSCOPE_CL, tableName=CLIENT_SCOPE_CLIENT; dropIndex indexName=IDX_CL_CLSCOPE, tableName=CLIENT_SCOPE_CLIENT \N 4.8.0 \N \N 3274862955 -13.0.0-increase-column-size-federated keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.190613 96 EXECUTED 8:9d11b619db2ae27c25853b8a37cd0dea modifyDataType columnName=CLIENT_ID, tableName=CLIENT_SCOPE_CLIENT; modifyDataType columnName=SCOPE_ID, tableName=CLIENT_SCOPE_CLIENT \N 4.8.0 \N \N 3274862955 -13.0.0-KEYCLOAK-17992-recreate-constraints keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.193934 97 MARK_RAN 8:3002bb3997451bb9e8bac5c5cd8d6327 addNotNullConstraint columnName=CLIENT_ID, tableName=CLIENT_SCOPE_CLIENT; addNotNullConstraint columnName=SCOPE_ID, tableName=CLIENT_SCOPE_CLIENT; addPrimaryKey constraintName=C_CLI_SCOPE_BIND, tableName=CLIENT_SCOPE_CLIENT; createIndex indexName=... \N 4.8.0 \N \N 3274862955 -json-string-accomodation-fixed keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.202965 98 EXECUTED 8:dfbee0d6237a23ef4ccbb7a4e063c163 addColumn tableName=REALM_ATTRIBUTE; update tableName=REALM_ATTRIBUTE; dropColumn columnName=VALUE, tableName=REALM_ATTRIBUTE; renameColumn newColumnName=VALUE, oldColumnName=VALUE_NEW, tableName=REALM_ATTRIBUTE \N 4.8.0 \N \N 3274862955 -14.0.0-KEYCLOAK-11019 keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.212244 99 EXECUTED 8:75f3e372df18d38c62734eebb986b960 createIndex indexName=IDX_OFFLINE_CSS_PRELOAD, tableName=OFFLINE_CLIENT_SESSION; createIndex indexName=IDX_OFFLINE_USS_BY_USER, tableName=OFFLINE_USER_SESSION; createIndex indexName=IDX_OFFLINE_USS_BY_USERSESS, tableName=OFFLINE_USER_SESSION \N 4.8.0 \N \N 3274862955 -14.0.0-KEYCLOAK-18286 keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.2164 100 MARK_RAN 8:7fee73eddf84a6035691512c85637eef createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 -14.0.0-KEYCLOAK-18286-revert keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.227895 101 MARK_RAN 8:7a11134ab12820f999fbf3bb13c3adc8 dropIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 -14.0.0-KEYCLOAK-18286-supported-dbs keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.235491 102 EXECUTED 8:c0f6eaac1f3be773ffe54cb5b8482b70 createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 -14.0.0-KEYCLOAK-18286-unsupported-dbs keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.238498 103 MARK_RAN 8:18186f0008b86e0f0f49b0c4d0e842ac createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 -KEYCLOAK-17267-add-index-to-user-attributes keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.24435 104 EXECUTED 8:09c2780bcb23b310a7019d217dc7b433 createIndex indexName=IDX_USER_ATTRIBUTE_NAME, tableName=USER_ATTRIBUTE \N 4.8.0 \N \N 3274862955 -KEYCLOAK-18146-add-saml-art-binding-identifier keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.250444 105 EXECUTED 8:276a44955eab693c970a42880197fff2 customChange \N 4.8.0 \N \N 3274862955 -15.0.0-KEYCLOAK-18467 keycloak META-INF/jpa-changelog-15.0.0.xml 2023-01-09 14:34:23.261701 106 EXECUTED 8:ba8ee3b694d043f2bfc1a1079d0760d7 addColumn tableName=REALM_LOCALIZATIONS; update tableName=REALM_LOCALIZATIONS; dropColumn columnName=TEXTS, tableName=REALM_LOCALIZATIONS; renameColumn newColumnName=TEXTS, oldColumnName=TEXTS_NEW, tableName=REALM_LOCALIZATIONS; addNotNullConstrai... \N 4.8.0 \N \N 3274862955 -17.0.0-9562 keycloak META-INF/jpa-changelog-17.0.0.xml 2023-01-09 14:34:23.269577 107 EXECUTED 8:5e06b1d75f5d17685485e610c2851b17 createIndex indexName=IDX_USER_SERVICE_ACCOUNT, tableName=USER_ENTITY \N 4.8.0 \N \N 3274862955 -18.0.0-10625-IDX_ADMIN_EVENT_TIME keycloak META-INF/jpa-changelog-18.0.0.xml 2023-01-09 14:34:23.276738 108 EXECUTED 8:4b80546c1dc550ac552ee7b24a4ab7c0 createIndex indexName=IDX_ADMIN_EVENT_TIME, tableName=ADMIN_EVENT_ENTITY \N 4.8.0 \N \N 3274862955 -19.0.0-10135 keycloak META-INF/jpa-changelog-19.0.0.xml 2023-01-09 14:34:23.297485 109 EXECUTED 8:af510cd1bb2ab6339c45372f3e491696 customChange \N 4.8.0 \N \N 3274862955 -20.0.0-12964-supported-dbs keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.305463 110 EXECUTED 8:05c99fc610845ef66ee812b7921af0ef createIndex indexName=IDX_GROUP_ATT_BY_NAME_VALUE, tableName=GROUP_ATTRIBUTE \N 4.8.0 \N \N 3274862955 -20.0.0-12964-unsupported-dbs keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.309005 111 MARK_RAN 8:314e803baf2f1ec315b3464e398b8247 createIndex indexName=IDX_GROUP_ATT_BY_NAME_VALUE, tableName=GROUP_ATTRIBUTE \N 4.8.0 \N \N 3274862955 -client-attributes-string-accomodation-fixed keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.318788 112 EXECUTED 8:56e4677e7e12556f70b604c573840100 addColumn tableName=CLIENT_ATTRIBUTES; update tableName=CLIENT_ATTRIBUTES; dropColumn columnName=VALUE, tableName=CLIENT_ATTRIBUTES; renameColumn newColumnName=VALUE, oldColumnName=VALUE_NEW, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +3.4.2 keycloak META-INF/jpa-changelog-3.4.2.xml 2022-02-02 16:47:26.786619 53 EXECUTED 9:8f23e334dbc59f82e0a328373ca6ced0 update tableName=REALM \N 3.5.4 \N \N 3820445829 +1.0.0.Final-KEYCLOAK-5461 sthorger@redhat.com META-INF/jpa-changelog-1.0.0.Final.xml 2022-02-02 16:47:26.017844 1 EXECUTED 9:6f1016664e21e16d26517a4418f5e3df createTable tableName=APPLICATION_DEFAULT_ROLES; createTable tableName=CLIENT; createTable tableName=CLIENT_SESSION; createTable tableName=CLIENT_SESSION_ROLE; createTable tableName=COMPOSITE_ROLE; createTable tableName=CREDENTIAL; createTable tab... \N 3.5.4 \N \N 3820445829 +1.0.0.Final-KEYCLOAK-5461 sthorger@redhat.com META-INF/db2-jpa-changelog-1.0.0.Final.xml 2022-02-02 16:47:26.03122 2 MARK_RAN 9:828775b1596a07d1200ba1d49e5e3941 createTable tableName=APPLICATION_DEFAULT_ROLES; createTable tableName=CLIENT; createTable tableName=CLIENT_SESSION; createTable tableName=CLIENT_SESSION_ROLE; createTable tableName=COMPOSITE_ROLE; createTable tableName=CREDENTIAL; createTable tab... \N 3.5.4 \N \N 3820445829 +1.1.0.Beta1 sthorger@redhat.com META-INF/jpa-changelog-1.1.0.Beta1.xml 2022-02-02 16:47:26.06085 3 EXECUTED 9:5f090e44a7d595883c1fb61f4b41fd38 delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=CLIENT_ATTRIBUTES; createTable tableName=CLIENT_SESSION_NOTE; createTable tableName=APP_NODE_REGISTRATIONS; addColumn table... \N 3.5.4 \N \N 3820445829 +1.1.0.Final sthorger@redhat.com META-INF/jpa-changelog-1.1.0.Final.xml 2022-02-02 16:47:26.065284 4 EXECUTED 9:c07e577387a3d2c04d1adc9aaad8730e renameColumn newColumnName=EVENT_TIME, oldColumnName=TIME, tableName=EVENT_ENTITY \N 3.5.4 \N \N 3820445829 +1.2.0.Beta1 psilva@redhat.com META-INF/jpa-changelog-1.2.0.Beta1.xml 2022-02-02 16:47:26.130908 5 EXECUTED 9:b68ce996c655922dbcd2fe6b6ae72686 delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=PROTOCOL_MAPPER; createTable tableName=PROTOCOL_MAPPER_CONFIG; createTable tableName=... \N 3.5.4 \N \N 3820445829 +1.2.0.Beta1 psilva@redhat.com META-INF/db2-jpa-changelog-1.2.0.Beta1.xml 2022-02-02 16:47:26.133863 6 MARK_RAN 9:543b5c9989f024fe35c6f6c5a97de88e delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION; createTable tableName=PROTOCOL_MAPPER; createTable tableName=PROTOCOL_MAPPER_CONFIG; createTable tableName=... \N 3.5.4 \N \N 3820445829 +1.2.0.RC1 bburke@redhat.com META-INF/jpa-changelog-1.2.0.CR1.xml 2022-02-02 16:47:26.183318 7 EXECUTED 9:765afebbe21cf5bbca048e632df38336 delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=MIGRATION_MODEL; createTable tableName=IDENTITY_P... \N 3.5.4 \N \N 3820445829 +1.2.0.RC1 bburke@redhat.com META-INF/db2-jpa-changelog-1.2.0.CR1.xml 2022-02-02 16:47:26.186858 8 MARK_RAN 9:db4a145ba11a6fdaefb397f6dbf829a1 delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=MIGRATION_MODEL; createTable tableName=IDENTITY_P... \N 3.5.4 \N \N 3820445829 +1.2.0.Final keycloak META-INF/jpa-changelog-1.2.0.Final.xml 2022-02-02 16:47:26.19172 9 EXECUTED 9:9d05c7be10cdb873f8bcb41bc3a8ab23 update tableName=CLIENT; update tableName=CLIENT; update tableName=CLIENT \N 3.5.4 \N \N 3820445829 +1.3.0 bburke@redhat.com META-INF/jpa-changelog-1.3.0.xml 2022-02-02 16:47:26.242162 10 EXECUTED 9:18593702353128d53111f9b1ff0b82b8 delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete tableName=USER_SESSION; createTable tableName=ADMI... \N 3.5.4 \N \N 3820445829 +1.4.0 bburke@redhat.com META-INF/jpa-changelog-1.4.0.xml 2022-02-02 16:47:26.275929 11 EXECUTED 9:6122efe5f090e41a85c0f1c9e52cbb62 delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 +1.4.0 bburke@redhat.com META-INF/db2-jpa-changelog-1.4.0.xml 2022-02-02 16:47:26.278548 12 MARK_RAN 9:e1ff28bf7568451453f844c5d54bb0b5 delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 +1.5.0 bburke@redhat.com META-INF/jpa-changelog-1.5.0.xml 2022-02-02 16:47:26.287616 13 EXECUTED 9:7af32cd8957fbc069f796b61217483fd delete tableName=CLIENT_SESSION_AUTH_STATUS; delete tableName=CLIENT_SESSION_ROLE; delete tableName=CLIENT_SESSION_PROT_MAPPER; delete tableName=CLIENT_SESSION_NOTE; delete tableName=CLIENT_SESSION; delete tableName=USER_SESSION_NOTE; delete table... \N 3.5.4 \N \N 3820445829 +1.6.1_from15 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.299798 14 EXECUTED 9:6005e15e84714cd83226bf7879f54190 addColumn tableName=REALM; addColumn tableName=KEYCLOAK_ROLE; addColumn tableName=CLIENT; createTable tableName=OFFLINE_USER_SESSION; createTable tableName=OFFLINE_CLIENT_SESSION; addPrimaryKey constraintName=CONSTRAINT_OFFL_US_SES_PK2, tableName=... \N 3.5.4 \N \N 3820445829 +1.6.1_from16-pre mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.302088 15 MARK_RAN 9:bf656f5a2b055d07f314431cae76f06c delete tableName=OFFLINE_CLIENT_SESSION; delete tableName=OFFLINE_USER_SESSION \N 3.5.4 \N \N 3820445829 +1.6.1_from16 mposolda@redhat.com META-INF/jpa-changelog-1.6.1.xml 2022-02-02 16:47:26.303889 16 MARK_RAN 9:f8dadc9284440469dcf71e25ca6ab99b dropPrimaryKey constraintName=CONSTRAINT_OFFLINE_US_SES_PK, tableName=OFFLINE_USER_SESSION; dropPrimaryKey constraintName=CONSTRAINT_OFFLINE_CL_SES_PK, tableName=OFFLINE_CLIENT_SESSION; addColumn tableName=OFFLINE_USER_SESSION; update tableName=OF... \N 3.5.4 \N \N 3820445829 +1.7.0 bburke@redhat.com META-INF/jpa-changelog-1.7.0.xml 2022-02-02 16:47:26.338791 18 EXECUTED 9:3368ff0be4c2855ee2dd9ca813b38d8e createTable tableName=KEYCLOAK_GROUP; createTable tableName=GROUP_ROLE_MAPPING; createTable tableName=GROUP_ATTRIBUTE; createTable tableName=USER_GROUP_MEMBERSHIP; createTable tableName=REALM_DEFAULT_GROUPS; addColumn tableName=IDENTITY_PROVIDER; ... \N 3.5.4 \N \N 3820445829 +1.8.0 mposolda@redhat.com META-INF/jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.381463 19 EXECUTED 9:8ac2fb5dd030b24c0570a763ed75ed20 addColumn tableName=IDENTITY_PROVIDER; createTable tableName=CLIENT_TEMPLATE; createTable tableName=CLIENT_TEMPLATE_ATTRIBUTES; createTable tableName=TEMPLATE_SCOPE_MAPPING; dropNotNullConstraint columnName=CLIENT_ID, tableName=PROTOCOL_MAPPER; ad... \N 3.5.4 \N \N 3820445829 +1.8.0-2 keycloak META-INF/jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.390165 20 EXECUTED 9:f91ddca9b19743db60e3057679810e6c dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; update tableName=CREDENTIAL \N 3.5.4 \N \N 3820445829 +1.8.0 mposolda@redhat.com META-INF/db2-jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.392862 21 MARK_RAN 9:831e82914316dc8a57dc09d755f23c51 addColumn tableName=IDENTITY_PROVIDER; createTable tableName=CLIENT_TEMPLATE; createTable tableName=CLIENT_TEMPLATE_ATTRIBUTES; createTable tableName=TEMPLATE_SCOPE_MAPPING; dropNotNullConstraint columnName=CLIENT_ID, tableName=PROTOCOL_MAPPER; ad... \N 3.5.4 \N \N 3820445829 +1.8.0-2 keycloak META-INF/db2-jpa-changelog-1.8.0.xml 2022-02-02 16:47:26.395652 22 MARK_RAN 9:f91ddca9b19743db60e3057679810e6c dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; update tableName=CREDENTIAL \N 3.5.4 \N \N 3820445829 +1.9.0 mposolda@redhat.com META-INF/jpa-changelog-1.9.0.xml 2022-02-02 16:47:26.40969 23 EXECUTED 9:bc3d0f9e823a69dc21e23e94c7a94bb1 update tableName=REALM; update tableName=REALM; update tableName=REALM; update tableName=REALM; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=REALM; update tableName=REALM; customChange; dr... \N 3.5.4 \N \N 3820445829 +1.9.1 keycloak META-INF/jpa-changelog-1.9.1.xml 2022-02-02 16:47:26.414344 24 EXECUTED 9:c9999da42f543575ab790e76439a2679 modifyDataType columnName=PRIVATE_KEY, tableName=REALM; modifyDataType columnName=PUBLIC_KEY, tableName=REALM; modifyDataType columnName=CERTIFICATE, tableName=REALM \N 3.5.4 \N \N 3820445829 +1.9.1 keycloak META-INF/db2-jpa-changelog-1.9.1.xml 2022-02-02 16:47:26.416193 25 MARK_RAN 9:0d6c65c6f58732d81569e77b10ba301d modifyDataType columnName=PRIVATE_KEY, tableName=REALM; modifyDataType columnName=CERTIFICATE, tableName=REALM \N 3.5.4 \N \N 3820445829 +1.9.2 keycloak META-INF/jpa-changelog-1.9.2.xml 2022-02-02 16:47:26.437367 26 EXECUTED 9:fc576660fc016ae53d2d4778d84d86d0 createIndex indexName=IDX_USER_EMAIL, tableName=USER_ENTITY; createIndex indexName=IDX_USER_ROLE_MAPPING, tableName=USER_ROLE_MAPPING; createIndex indexName=IDX_USER_GROUP_MAPPING, tableName=USER_GROUP_MEMBERSHIP; createIndex indexName=IDX_USER_CO... \N 3.5.4 \N \N 3820445829 +authz-2.0.0 psilva@redhat.com META-INF/jpa-changelog-authz-2.0.0.xml 2022-02-02 16:47:26.481647 27 EXECUTED 9:43ed6b0da89ff77206289e87eaa9c024 createTable tableName=RESOURCE_SERVER; addPrimaryKey constraintName=CONSTRAINT_FARS, tableName=RESOURCE_SERVER; addUniqueConstraint constraintName=UK_AU8TT6T700S9V50BU18WS5HA6, tableName=RESOURCE_SERVER; createTable tableName=RESOURCE_SERVER_RESOU... \N 3.5.4 \N \N 3820445829 +2.1.0-KEYCLOAK-5461 bburke@redhat.com META-INF/jpa-changelog-2.1.0.xml 2022-02-02 16:47:26.523006 29 EXECUTED 9:bd88e1f833df0420b01e114533aee5e8 createTable tableName=BROKER_LINK; createTable tableName=FED_USER_ATTRIBUTE; createTable tableName=FED_USER_CONSENT; createTable tableName=FED_USER_CONSENT_ROLE; createTable tableName=FED_USER_CONSENT_PROT_MAPPER; createTable tableName=FED_USER_CR... \N 3.5.4 \N \N 3820445829 +2.2.0 bburke@redhat.com META-INF/jpa-changelog-2.2.0.xml 2022-02-02 16:47:26.532066 30 EXECUTED 9:a7022af5267f019d020edfe316ef4371 addColumn tableName=ADMIN_EVENT_ENTITY; createTable tableName=CREDENTIAL_ATTRIBUTE; createTable tableName=FED_CREDENTIAL_ATTRIBUTE; modifyDataType columnName=VALUE, tableName=CREDENTIAL; addForeignKeyConstraint baseTableName=FED_CREDENTIAL_ATTRIBU... \N 3.5.4 \N \N 3820445829 +2.3.0 bburke@redhat.com META-INF/jpa-changelog-2.3.0.xml 2022-02-02 16:47:26.541837 31 EXECUTED 9:fc155c394040654d6a79227e56f5e25a createTable tableName=FEDERATED_USER; addPrimaryKey constraintName=CONSTR_FEDERATED_USER, tableName=FEDERATED_USER; dropDefaultValue columnName=TOTP, tableName=USER_ENTITY; dropColumn columnName=TOTP, tableName=USER_ENTITY; addColumn tableName=IDE... \N 3.5.4 \N \N 3820445829 +2.4.0 bburke@redhat.com META-INF/jpa-changelog-2.4.0.xml 2022-02-02 16:47:26.545809 32 EXECUTED 9:eac4ffb2a14795e5dc7b426063e54d88 customChange \N 3.5.4 \N \N 3820445829 +2.5.0 bburke@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.549823 33 EXECUTED 9:54937c05672568c4c64fc9524c1e9462 customChange; modifyDataType columnName=USER_ID, tableName=OFFLINE_USER_SESSION \N 3.5.4 \N \N 3820445829 +2.5.0-unicode-oracle hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.55176 34 MARK_RAN 9:3a32bace77c84d7678d035a7f5a8084e modifyDataType columnName=DESCRIPTION, tableName=AUTHENTICATION_FLOW; modifyDataType columnName=DESCRIPTION, tableName=CLIENT_TEMPLATE; modifyDataType columnName=DESCRIPTION, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=DESCRIPTION,... \N 3.5.4 \N \N 3820445829 +2.5.0-unicode-other-dbs hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.567305 35 EXECUTED 9:33d72168746f81f98ae3a1e8e0ca3554 modifyDataType columnName=DESCRIPTION, tableName=AUTHENTICATION_FLOW; modifyDataType columnName=DESCRIPTION, tableName=CLIENT_TEMPLATE; modifyDataType columnName=DESCRIPTION, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=DESCRIPTION,... \N 3.5.4 \N \N 3820445829 +2.5.0-duplicate-email-support slawomir@dabek.name META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.570727 36 EXECUTED 9:61b6d3d7a4c0e0024b0c839da283da0c addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 +2.5.0-unique-group-names hmlnarik@redhat.com META-INF/jpa-changelog-2.5.0.xml 2022-02-02 16:47:26.578396 37 EXECUTED 9:8dcac7bdf7378e7d823cdfddebf72fda addUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 +2.5.1 bburke@redhat.com META-INF/jpa-changelog-2.5.1.xml 2022-02-02 16:47:26.581391 38 EXECUTED 9:a2b870802540cb3faa72098db5388af3 addColumn tableName=FED_USER_CONSENT \N 3.5.4 \N \N 3820445829 +3.0.0 bburke@redhat.com META-INF/jpa-changelog-3.0.0.xml 2022-02-02 16:47:26.584204 39 EXECUTED 9:132a67499ba24bcc54fb5cbdcfe7e4c0 addColumn tableName=IDENTITY_PROVIDER \N 3.5.4 \N \N 3820445829 +3.2.0-fix keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.585877 40 MARK_RAN 9:938f894c032f5430f2b0fafb1a243462 addNotNullConstraint columnName=REALM_ID, tableName=CLIENT_INITIAL_ACCESS \N 3.5.4 \N \N 3820445829 +3.2.0-fix-with-keycloak-5416 keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.587657 41 MARK_RAN 9:845c332ff1874dc5d35974b0babf3006 dropIndex indexName=IDX_CLIENT_INIT_ACC_REALM, tableName=CLIENT_INITIAL_ACCESS; addNotNullConstraint columnName=REALM_ID, tableName=CLIENT_INITIAL_ACCESS; createIndex indexName=IDX_CLIENT_INIT_ACC_REALM, tableName=CLIENT_INITIAL_ACCESS \N 3.5.4 \N \N 3820445829 +3.2.0-fix-offline-sessions hmlnarik META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.591561 42 EXECUTED 9:fc86359c079781adc577c5a217e4d04c customChange \N 3.5.4 \N \N 3820445829 +3.2.0-fixed keycloak META-INF/jpa-changelog-3.2.0.xml 2022-02-02 16:47:26.669981 43 EXECUTED 9:59a64800e3c0d09b825f8a3b444fa8f4 addColumn tableName=REALM; dropPrimaryKey constraintName=CONSTRAINT_OFFL_CL_SES_PK2, tableName=OFFLINE_CLIENT_SESSION; dropColumn columnName=CLIENT_SESSION_ID, tableName=OFFLINE_CLIENT_SESSION; addPrimaryKey constraintName=CONSTRAINT_OFFL_CL_SES_P... \N 3.5.4 \N \N 3820445829 +3.3.0 keycloak META-INF/jpa-changelog-3.3.0.xml 2022-02-02 16:47:26.673701 44 EXECUTED 9:d48d6da5c6ccf667807f633fe489ce88 addColumn tableName=USER_ENTITY \N 3.5.4 \N \N 3820445829 +authz-3.4.0.CR1-resource-server-pk-change-part1 glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.679075 45 EXECUTED 9:dde36f7973e80d71fceee683bc5d2951 addColumn tableName=RESOURCE_SERVER_POLICY; addColumn tableName=RESOURCE_SERVER_RESOURCE; addColumn tableName=RESOURCE_SERVER_SCOPE \N 3.5.4 \N \N 3820445829 +authz-3.4.0.CR1-resource-server-pk-change-part2-KEYCLOAK-6095 hmlnarik@redhat.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.681987 46 EXECUTED 9:b855e9b0a406b34fa323235a0cf4f640 customChange \N 3.5.4 \N \N 3820445829 +authz-3.4.0.CR1-resource-server-pk-change-part3-fixed glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.683661 47 MARK_RAN 9:51abbacd7b416c50c4421a8cabf7927e dropIndex indexName=IDX_RES_SERV_POL_RES_SERV, tableName=RESOURCE_SERVER_POLICY; dropIndex indexName=IDX_RES_SRV_RES_RES_SRV, tableName=RESOURCE_SERVER_RESOURCE; dropIndex indexName=IDX_RES_SRV_SCOPE_RES_SRV, tableName=RESOURCE_SERVER_SCOPE \N 3.5.4 \N \N 3820445829 +authz-3.4.0.CR1-resource-server-pk-change-part3-fixed-nodropindex glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.702743 48 EXECUTED 9:bdc99e567b3398bac83263d375aad143 addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, tableName=RESOURCE_SERVER_POLICY; addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, tableName=RESOURCE_SERVER_RESOURCE; addNotNullConstraint columnName=RESOURCE_SERVER_CLIENT_ID, ... \N 3.5.4 \N \N 3820445829 +authn-3.4.0.CR1-refresh-token-max-reuse glavoie@gmail.com META-INF/jpa-changelog-authz-3.4.0.CR1.xml 2022-02-02 16:47:26.706593 49 EXECUTED 9:d198654156881c46bfba39abd7769e69 addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 +3.4.0 keycloak META-INF/jpa-changelog-3.4.0.xml 2022-02-02 16:47:26.734467 50 EXECUTED 9:cfdd8736332ccdd72c5256ccb42335db addPrimaryKey constraintName=CONSTRAINT_REALM_DEFAULT_ROLES, tableName=REALM_DEFAULT_ROLES; addPrimaryKey constraintName=CONSTRAINT_COMPOSITE_ROLE, tableName=COMPOSITE_ROLE; addPrimaryKey constraintName=CONSTR_REALM_DEFAULT_GROUPS, tableName=REALM... \N 3.5.4 \N \N 3820445829 +3.4.0-KEYCLOAK-5230 hmlnarik@redhat.com META-INF/jpa-changelog-3.4.0.xml 2022-02-02 16:47:26.78037 51 EXECUTED 9:7c84de3d9bd84d7f077607c1a4dcb714 createIndex indexName=IDX_FU_ATTRIBUTE, tableName=FED_USER_ATTRIBUTE; createIndex indexName=IDX_FU_CONSENT, tableName=FED_USER_CONSENT; createIndex indexName=IDX_FU_CONSENT_RU, tableName=FED_USER_CONSENT; createIndex indexName=IDX_FU_CREDENTIAL, t... \N 3.5.4 \N \N 3820445829 +3.4.1 psilva@redhat.com META-INF/jpa-changelog-3.4.1.xml 2022-02-02 16:47:26.783989 52 EXECUTED 9:5a6bb36cbefb6a9d6928452c0852af2d modifyDataType columnName=VALUE, tableName=CLIENT_ATTRIBUTES \N 3.5.4 \N \N 3820445829 +3.4.2-KEYCLOAK-5172 mkanis@redhat.com META-INF/jpa-changelog-3.4.2.xml 2022-02-02 16:47:26.788788 54 EXECUTED 9:9156214268f09d970cdf0e1564d866af update tableName=CLIENT \N 3.5.4 \N \N 3820445829 +4.0.0-KEYCLOAK-6335 bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.794881 55 EXECUTED 9:db806613b1ed154826c02610b7dbdf74 createTable tableName=CLIENT_AUTH_FLOW_BINDINGS; addPrimaryKey constraintName=C_CLI_FLOW_BIND, tableName=CLIENT_AUTH_FLOW_BINDINGS \N 3.5.4 \N \N 3820445829 +4.0.0-CLEANUP-UNUSED-TABLE bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.799493 56 EXECUTED 9:229a041fb72d5beac76bb94a5fa709de dropTable tableName=CLIENT_IDENTITY_PROV_MAPPING \N 3.5.4 \N \N 3820445829 +4.0.0-KEYCLOAK-6228 bburke@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.810686 57 EXECUTED 9:079899dade9c1e683f26b2aa9ca6ff04 dropUniqueConstraint constraintName=UK_JKUWUVD56ONTGSUHOGM8UEWRT, tableName=USER_CONSENT; dropNotNullConstraint columnName=CLIENT_ID, tableName=USER_CONSENT; addColumn tableName=USER_CONSENT; addUniqueConstraint constraintName=UK_JKUWUVD56ONTGSUHO... \N 3.5.4 \N \N 3820445829 +4.0.0-KEYCLOAK-5579-fixed mposolda@redhat.com META-INF/jpa-changelog-4.0.0.xml 2022-02-02 16:47:26.861332 58 EXECUTED 9:139b79bcbbfe903bb1c2d2a4dbf001d9 dropForeignKeyConstraint baseTableName=CLIENT_TEMPLATE_ATTRIBUTES, constraintName=FK_CL_TEMPL_ATTR_TEMPL; renameTable newTableName=CLIENT_SCOPE_ATTRIBUTES, oldTableName=CLIENT_TEMPLATE_ATTRIBUTES; renameColumn newColumnName=SCOPE_ID, oldColumnName... \N 3.5.4 \N \N 3820445829 +authz-4.0.0.CR1 psilva@redhat.com META-INF/jpa-changelog-authz-4.0.0.CR1.xml 2022-02-02 16:47:26.877018 59 EXECUTED 9:b55738ad889860c625ba2bf483495a04 createTable tableName=RESOURCE_SERVER_PERM_TICKET; addPrimaryKey constraintName=CONSTRAINT_FAPMT, tableName=RESOURCE_SERVER_PERM_TICKET; addForeignKeyConstraint baseTableName=RESOURCE_SERVER_PERM_TICKET, constraintName=FK_FRSRHO213XCX4WNKOG82SSPMT... \N 3.5.4 \N \N 3820445829 +authz-4.0.0.Beta3 psilva@redhat.com META-INF/jpa-changelog-authz-4.0.0.Beta3.xml 2022-02-02 16:47:26.881203 60 EXECUTED 9:e0057eac39aa8fc8e09ac6cfa4ae15fe addColumn tableName=RESOURCE_SERVER_POLICY; addColumn tableName=RESOURCE_SERVER_PERM_TICKET; addForeignKeyConstraint baseTableName=RESOURCE_SERVER_PERM_TICKET, constraintName=FK_FRSRPO2128CX4WNKOG82SSRFY, referencedTableName=RESOURCE_SERVER_POLICY \N 3.5.4 \N \N 3820445829 +authz-4.2.0.Final mhajas@redhat.com META-INF/jpa-changelog-authz-4.2.0.Final.xml 2022-02-02 16:47:26.886177 61 EXECUTED 9:42a33806f3a0443fe0e7feeec821326c createTable tableName=RESOURCE_URIS; addForeignKeyConstraint baseTableName=RESOURCE_URIS, constraintName=FK_RESOURCE_SERVER_URIS, referencedTableName=RESOURCE_SERVER_RESOURCE; customChange; dropColumn columnName=URI, tableName=RESOURCE_SERVER_RESO... \N 3.5.4 \N \N 3820445829 +authz-4.2.0.Final-KEYCLOAK-9944 hmlnarik@redhat.com META-INF/jpa-changelog-authz-4.2.0.Final.xml 2022-02-02 16:47:26.890482 62 EXECUTED 9:9968206fca46eecc1f51db9c024bfe56 addPrimaryKey constraintName=CONSTRAINT_RESOUR_URIS_PK, tableName=RESOURCE_URIS \N 3.5.4 \N \N 3820445829 +4.2.0-KEYCLOAK-6313 wadahiro@gmail.com META-INF/jpa-changelog-4.2.0.xml 2022-02-02 16:47:26.893518 63 EXECUTED 9:92143a6daea0a3f3b8f598c97ce55c3d addColumn tableName=REQUIRED_ACTION_PROVIDER \N 3.5.4 \N \N 3820445829 +4.3.0-KEYCLOAK-7984 wadahiro@gmail.com META-INF/jpa-changelog-4.3.0.xml 2022-02-02 16:47:26.895621 64 EXECUTED 9:82bab26a27195d889fb0429003b18f40 update tableName=REQUIRED_ACTION_PROVIDER \N 3.5.4 \N \N 3820445829 +4.6.0-KEYCLOAK-7950 psilva@redhat.com META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.89756 65 EXECUTED 9:e590c88ddc0b38b0ae4249bbfcb5abc3 update tableName=RESOURCE_SERVER_RESOURCE \N 3.5.4 \N \N 3820445829 +4.6.0-KEYCLOAK-8377 keycloak META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.908059 66 EXECUTED 9:5c1f475536118dbdc38d5d7977950cc0 createTable tableName=ROLE_ATTRIBUTE; addPrimaryKey constraintName=CONSTRAINT_ROLE_ATTRIBUTE_PK, tableName=ROLE_ATTRIBUTE; addForeignKeyConstraint baseTableName=ROLE_ATTRIBUTE, constraintName=FK_ROLE_ATTRIBUTE_ID, referencedTableName=KEYCLOAK_ROLE... \N 3.5.4 \N \N 3820445829 +4.6.0-KEYCLOAK-8555 gideonray@gmail.com META-INF/jpa-changelog-4.6.0.xml 2022-02-02 16:47:26.912693 67 EXECUTED 9:e7c9f5f9c4d67ccbbcc215440c718a17 createIndex indexName=IDX_COMPONENT_PROVIDER_TYPE, tableName=COMPONENT \N 3.5.4 \N \N 3820445829 +4.7.0-KEYCLOAK-1267 sguilhen@redhat.com META-INF/jpa-changelog-4.7.0.xml 2022-02-02 16:47:26.915771 68 EXECUTED 9:88e0bfdda924690d6f4e430c53447dd5 addColumn tableName=REALM \N 3.5.4 \N \N 3820445829 +4.7.0-KEYCLOAK-7275 keycloak META-INF/jpa-changelog-4.7.0.xml 2022-02-02 16:47:26.924465 69 EXECUTED 9:f53177f137e1c46b6a88c59ec1cb5218 renameColumn newColumnName=CREATED_ON, oldColumnName=LAST_SESSION_REFRESH, tableName=OFFLINE_USER_SESSION; addNotNullConstraint columnName=CREATED_ON, tableName=OFFLINE_USER_SESSION; addColumn tableName=OFFLINE_USER_SESSION; customChange; createIn... \N 3.5.4 \N \N 3820445829 +4.8.0-KEYCLOAK-8835 sguilhen@redhat.com META-INF/jpa-changelog-4.8.0.xml 2022-02-02 16:47:26.928034 70 EXECUTED 9:a74d33da4dc42a37ec27121580d1459f addNotNullConstraint columnName=SSO_MAX_LIFESPAN_REMEMBER_ME, tableName=REALM; addNotNullConstraint columnName=SSO_IDLE_TIMEOUT_REMEMBER_ME, tableName=REALM \N 3.5.4 \N \N 3820445829 +authz-7.0.0-KEYCLOAK-10443 psilva@redhat.com META-INF/jpa-changelog-authz-7.0.0.xml 2022-02-02 16:47:26.93061 71 EXECUTED 9:fd4ade7b90c3b67fae0bfcfcb42dfb5f addColumn tableName=RESOURCE_SERVER \N 3.5.4 \N \N 3820445829 +8.0.0-adding-credential-columns keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.933771 72 EXECUTED 9:aa072ad090bbba210d8f18781b8cebf4 addColumn tableName=CREDENTIAL; addColumn tableName=FED_USER_CREDENTIAL \N 3.5.4 \N \N 3820445829 +8.0.0-credential-cleanup-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.945819 75 EXECUTED 9:2b9cc12779be32c5b40e2e67711a218b dropDefaultValue columnName=COUNTER, tableName=CREDENTIAL; dropDefaultValue columnName=DIGITS, tableName=CREDENTIAL; dropDefaultValue columnName=PERIOD, tableName=CREDENTIAL; dropDefaultValue columnName=ALGORITHM, tableName=CREDENTIAL; dropColumn ... \N 3.5.4 \N \N 3820445829 +8.0.0-resource-tag-support keycloak META-INF/jpa-changelog-8.0.0.xml 2022-02-02 16:47:26.950255 76 EXECUTED 9:91fa186ce7a5af127a2d7a91ee083cc5 addColumn tableName=MIGRATION_MODEL; createIndex indexName=IDX_UPDATE_TIME, tableName=MIGRATION_MODEL \N 3.5.4 \N \N 3820445829 +9.0.0-always-display-client keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.955505 77 EXECUTED 9:6335e5c94e83a2639ccd68dd24e2e5ad addColumn tableName=CLIENT \N 3.5.4 \N \N 3820445829 +9.0.0-drop-constraints-for-column-increase keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.957216 78 MARK_RAN 9:6bdb5658951e028bfe16fa0a8228b530 dropUniqueConstraint constraintName=UK_FRSR6T700S9V50BU18WS5PMT, tableName=RESOURCE_SERVER_PERM_TICKET; dropUniqueConstraint constraintName=UK_FRSR6T700S9V50BU18WS5HA6, tableName=RESOURCE_SERVER_RESOURCE; dropPrimaryKey constraintName=CONSTRAINT_O... \N 3.5.4 \N \N 3820445829 +9.0.0-increase-column-size-federated-fk keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.966746 79 EXECUTED 9:d5bc15a64117ccad481ce8792d4c608f modifyDataType columnName=CLIENT_ID, tableName=FED_USER_CONSENT; modifyDataType columnName=CLIENT_REALM_CONSTRAINT, tableName=KEYCLOAK_ROLE; modifyDataType columnName=OWNER, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=CLIENT_ID, ta... \N 3.5.4 \N \N 3820445829 +9.0.0-recreate-constraints-after-column-increase keycloak META-INF/jpa-changelog-9.0.0.xml 2022-02-02 16:47:26.969643 80 MARK_RAN 9:077cba51999515f4d3e7ad5619ab592c addNotNullConstraint columnName=CLIENT_ID, tableName=OFFLINE_CLIENT_SESSION; addNotNullConstraint columnName=OWNER, tableName=RESOURCE_SERVER_PERM_TICKET; addNotNullConstraint columnName=REQUESTER, tableName=RESOURCE_SERVER_PERM_TICKET; addNotNull... \N 3.5.4 \N \N 3820445829 +9.0.1-add-index-to-client.client_id keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.975764 81 EXECUTED 9:be969f08a163bf47c6b9e9ead8ac2afb createIndex indexName=IDX_CLIENT_ID, tableName=CLIENT \N 3.5.4 \N \N 3820445829 +9.0.1-KEYCLOAK-12579-drop-constraints keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.977227 82 MARK_RAN 9:6d3bb4408ba5a72f39bd8a0b301ec6e3 dropUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 +9.0.1-KEYCLOAK-12579-add-not-null-constraint keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.980058 83 EXECUTED 9:966bda61e46bebf3cc39518fbed52fa7 addNotNullConstraint columnName=PARENT_GROUP, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 +9.0.1-KEYCLOAK-12579-recreate-constraints keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.981645 84 MARK_RAN 9:8dcac7bdf7378e7d823cdfddebf72fda addUniqueConstraint constraintName=SIBLING_NAMES, tableName=KEYCLOAK_GROUP \N 3.5.4 \N \N 3820445829 +9.0.1-add-index-to-events keycloak META-INF/jpa-changelog-9.0.1.xml 2022-02-02 16:47:26.985465 85 EXECUTED 9:7d93d602352a30c0c317e6a609b56599 createIndex indexName=IDX_EVENT_TIME, tableName=EVENT_ENTITY \N 3.5.4 \N \N 3820445829 +map-remove-ri keycloak META-INF/jpa-changelog-11.0.0.xml 2022-02-02 16:47:26.98869 86 EXECUTED 9:71c5969e6cdd8d7b6f47cebc86d37627 dropForeignKeyConstraint baseTableName=REALM, constraintName=FK_TRAF444KK6QRKMS7N56AIWQ5Y; dropForeignKeyConstraint baseTableName=KEYCLOAK_ROLE, constraintName=FK_KJHO5LE2C0RAL09FL8CM9WFW9 \N 3.5.4 \N \N 3820445829 +map-remove-ri keycloak META-INF/jpa-changelog-12.0.0.xml 2022-02-02 16:47:26.992854 87 EXECUTED 9:a9ba7d47f065f041b7da856a81762021 dropForeignKeyConstraint baseTableName=REALM_DEFAULT_GROUPS, constraintName=FK_DEF_GROUPS_GROUP; dropForeignKeyConstraint baseTableName=REALM_DEFAULT_ROLES, constraintName=FK_H4WPD7W4HSOOLNI3H0SW7BTJE; dropForeignKeyConstraint baseTableName=CLIENT... \N 3.5.4 \N \N 3820445829 +12.1.0-add-realm-localization-table keycloak META-INF/jpa-changelog-12.0.0.xml 2022-02-02 16:47:26.999694 88 EXECUTED 9:fffabce2bc01e1a8f5110d5278500065 createTable tableName=REALM_LOCALIZATIONS; addPrimaryKey tableName=REALM_LOCALIZATIONS \N 3.5.4 \N \N 3820445829 +8.0.0-updating-credential-data-not-oracle-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2023-01-09 14:34:23.080082 89 MARK_RAN 9:1ae6be29bab7c2aa376f6983b932be37 update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 4.8.0 \N \N 3274862955 +8.0.0-updating-credential-data-oracle-fixed keycloak META-INF/jpa-changelog-8.0.0.xml 2023-01-09 14:34:23.099857 90 MARK_RAN 9:14706f286953fc9a25286dbd8fb30d97 update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL; update tableName=FED_USER_CREDENTIAL \N 4.8.0 \N \N 3274862955 +default-roles keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.144776 91 EXECUTED 9:fa8a5b5445e3857f4b010bafb5009957 addColumn tableName=REALM; customChange \N 4.8.0 \N \N 3274862955 +default-roles-cleanup keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.155298 92 EXECUTED 9:67ac3241df9a8582d591c5ed87125f39 dropTable tableName=REALM_DEFAULT_ROLES; dropTable tableName=CLIENT_DEFAULT_ROLES \N 4.8.0 \N \N 3274862955 +13.0.0-KEYCLOAK-16844 keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.162911 93 EXECUTED 9:ad1194d66c937e3ffc82386c050ba089 createIndex indexName=IDX_OFFLINE_USS_PRELOAD, tableName=OFFLINE_USER_SESSION \N 4.8.0 \N \N 3274862955 +map-remove-ri-13.0.0 keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.17617 94 EXECUTED 9:d9be619d94af5a2f5d07b9f003543b91 dropForeignKeyConstraint baseTableName=DEFAULT_CLIENT_SCOPE, constraintName=FK_R_DEF_CLI_SCOPE_SCOPE; dropForeignKeyConstraint baseTableName=CLIENT_SCOPE_CLIENT, constraintName=FK_C_CLI_SCOPE_SCOPE; dropForeignKeyConstraint baseTableName=CLIENT_SC... \N 4.8.0 \N \N 3274862955 +13.0.0-KEYCLOAK-17992-drop-constraints keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.1803 95 MARK_RAN 9:544d201116a0fcc5a5da0925fbbc3bde dropPrimaryKey constraintName=C_CLI_SCOPE_BIND, tableName=CLIENT_SCOPE_CLIENT; dropIndex indexName=IDX_CLSCOPE_CL, tableName=CLIENT_SCOPE_CLIENT; dropIndex indexName=IDX_CL_CLSCOPE, tableName=CLIENT_SCOPE_CLIENT \N 4.8.0 \N \N 3274862955 +13.0.0-increase-column-size-federated keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.190613 96 EXECUTED 9:43c0c1055b6761b4b3e89de76d612ccf modifyDataType columnName=CLIENT_ID, tableName=CLIENT_SCOPE_CLIENT; modifyDataType columnName=SCOPE_ID, tableName=CLIENT_SCOPE_CLIENT \N 4.8.0 \N \N 3274862955 +13.0.0-KEYCLOAK-17992-recreate-constraints keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.193934 97 MARK_RAN 9:8bd711fd0330f4fe980494ca43ab1139 addNotNullConstraint columnName=CLIENT_ID, tableName=CLIENT_SCOPE_CLIENT; addNotNullConstraint columnName=SCOPE_ID, tableName=CLIENT_SCOPE_CLIENT; addPrimaryKey constraintName=C_CLI_SCOPE_BIND, tableName=CLIENT_SCOPE_CLIENT; createIndex indexName=... \N 4.8.0 \N \N 3274862955 +json-string-accomodation-fixed keycloak META-INF/jpa-changelog-13.0.0.xml 2023-01-09 14:34:23.202965 98 EXECUTED 9:e07d2bc0970c348bb06fb63b1f82ddbf addColumn tableName=REALM_ATTRIBUTE; update tableName=REALM_ATTRIBUTE; dropColumn columnName=VALUE, tableName=REALM_ATTRIBUTE; renameColumn newColumnName=VALUE, oldColumnName=VALUE_NEW, tableName=REALM_ATTRIBUTE \N 4.8.0 \N \N 3274862955 +14.0.0-KEYCLOAK-11019 keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.212244 99 EXECUTED 9:24fb8611e97f29989bea412aa38d12b7 createIndex indexName=IDX_OFFLINE_CSS_PRELOAD, tableName=OFFLINE_CLIENT_SESSION; createIndex indexName=IDX_OFFLINE_USS_BY_USER, tableName=OFFLINE_USER_SESSION; createIndex indexName=IDX_OFFLINE_USS_BY_USERSESS, tableName=OFFLINE_USER_SESSION \N 4.8.0 \N \N 3274862955 +14.0.0-KEYCLOAK-18286 keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.2164 100 MARK_RAN 9:259f89014ce2506ee84740cbf7163aa7 createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +14.0.0-KEYCLOAK-18286-revert keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.227895 101 MARK_RAN 9:04baaf56c116ed19951cbc2cca584022 dropIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +14.0.0-KEYCLOAK-18286-supported-dbs keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.235491 102 EXECUTED 9:60ca84a0f8c94ec8c3504a5a3bc88ee8 createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +14.0.0-KEYCLOAK-18286-unsupported-dbs keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.238498 103 MARK_RAN 9:d3d977031d431db16e2c181ce49d73e9 createIndex indexName=IDX_CLIENT_ATT_BY_NAME_VALUE, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +KEYCLOAK-17267-add-index-to-user-attributes keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.24435 104 EXECUTED 9:0b305d8d1277f3a89a0a53a659ad274c createIndex indexName=IDX_USER_ATTRIBUTE_NAME, tableName=USER_ATTRIBUTE \N 4.8.0 \N \N 3274862955 +KEYCLOAK-18146-add-saml-art-binding-identifier keycloak META-INF/jpa-changelog-14.0.0.xml 2023-01-09 14:34:23.250444 105 EXECUTED 9:2c374ad2cdfe20e2905a84c8fac48460 customChange \N 4.8.0 \N \N 3274862955 +15.0.0-KEYCLOAK-18467 keycloak META-INF/jpa-changelog-15.0.0.xml 2023-01-09 14:34:23.261701 106 EXECUTED 9:47a760639ac597360a8219f5b768b4de addColumn tableName=REALM_LOCALIZATIONS; update tableName=REALM_LOCALIZATIONS; dropColumn columnName=TEXTS, tableName=REALM_LOCALIZATIONS; renameColumn newColumnName=TEXTS, oldColumnName=TEXTS_NEW, tableName=REALM_LOCALIZATIONS; addNotNullConstrai... \N 4.8.0 \N \N 3274862955 +17.0.0-9562 keycloak META-INF/jpa-changelog-17.0.0.xml 2023-01-09 14:34:23.269577 107 EXECUTED 9:a6272f0576727dd8cad2522335f5d99e createIndex indexName=IDX_USER_SERVICE_ACCOUNT, tableName=USER_ENTITY \N 4.8.0 \N \N 3274862955 +18.0.0-10625-IDX_ADMIN_EVENT_TIME keycloak META-INF/jpa-changelog-18.0.0.xml 2023-01-09 14:34:23.276738 108 EXECUTED 9:015479dbd691d9cc8669282f4828c41d createIndex indexName=IDX_ADMIN_EVENT_TIME, tableName=ADMIN_EVENT_ENTITY \N 4.8.0 \N \N 3274862955 +19.0.0-10135 keycloak META-INF/jpa-changelog-19.0.0.xml 2023-01-09 14:34:23.297485 109 EXECUTED 9:9518e495fdd22f78ad6425cc30630221 customChange \N 4.8.0 \N \N 3274862955 +20.0.0-12964-supported-dbs keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.305463 110 EXECUTED 9:e5f243877199fd96bcc842f27a1656ac createIndex indexName=IDX_GROUP_ATT_BY_NAME_VALUE, tableName=GROUP_ATTRIBUTE \N 4.8.0 \N \N 3274862955 +20.0.0-12964-unsupported-dbs keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.309005 111 MARK_RAN 9:1a6fcaa85e20bdeae0a9ce49b41946a5 createIndex indexName=IDX_GROUP_ATT_BY_NAME_VALUE, tableName=GROUP_ATTRIBUTE \N 4.8.0 \N \N 3274862955 +client-attributes-string-accomodation-fixed keycloak META-INF/jpa-changelog-20.0.0.xml 2023-01-09 14:34:23.318788 112 EXECUTED 9:3f332e13e90739ed0c35b0b25b7822ca addColumn tableName=CLIENT_ATTRIBUTES; update tableName=CLIENT_ATTRIBUTES; dropColumn columnName=VALUE, tableName=CLIENT_ATTRIBUTES; renameColumn newColumnName=VALUE, oldColumnName=VALUE_NEW, tableName=CLIENT_ATTRIBUTES \N 4.8.0 \N \N 3274862955 +21.0.2-17277 keycloak META-INF/jpa-changelog-21.0.2.xml 2024-02-14 09:01:09.307684 113 EXECUTED 9:7ee1f7a3fb8f5588f171fb9a6ab623c0 customChange \N 4.23.2 \N \N 7901269232 +21.1.0-19404 keycloak META-INF/jpa-changelog-21.1.0.xml 2024-02-14 09:01:09.324282 114 EXECUTED 9:3d7e830b52f33676b9d64f7f2b2ea634 modifyDataType columnName=DECISION_STRATEGY, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=LOGIC, tableName=RESOURCE_SERVER_POLICY; modifyDataType columnName=POLICY_ENFORCE_MODE, tableName=RESOURCE_SERVER \N 4.23.2 \N \N 7901269232 +21.1.0-19404-2 keycloak META-INF/jpa-changelog-21.1.0.xml 2024-02-14 09:01:09.327044 115 MARK_RAN 9:627d032e3ef2c06c0e1f73d2ae25c26c addColumn tableName=RESOURCE_SERVER_POLICY; update tableName=RESOURCE_SERVER_POLICY; dropColumn columnName=DECISION_STRATEGY, tableName=RESOURCE_SERVER_POLICY; renameColumn newColumnName=DECISION_STRATEGY, oldColumnName=DECISION_STRATEGY_NEW, tabl... \N 4.23.2 \N \N 7901269232 +22.0.0-17484-updated keycloak META-INF/jpa-changelog-22.0.0.xml 2024-02-14 09:01:09.332189 116 EXECUTED 9:90af0bfd30cafc17b9f4d6eccd92b8b3 customChange \N 4.23.2 \N \N 7901269232 +22.0.5-24031 keycloak META-INF/jpa-changelog-22.0.0.xml 2024-02-14 09:01:09.333603 117 MARK_RAN 9:a60d2d7b315ec2d3eba9e2f145f9df28 customChange \N 4.23.2 \N \N 7901269232 +23.0.0-12062 keycloak META-INF/jpa-changelog-23.0.0.xml 2024-02-14 09:01:09.340927 118 EXECUTED 9:2168fbe728fec46ae9baf15bf80927b8 addColumn tableName=COMPONENT_CONFIG; update tableName=COMPONENT_CONFIG; dropColumn columnName=VALUE, tableName=COMPONENT_CONFIG; renameColumn newColumnName=VALUE, oldColumnName=VALUE_NEW, tableName=COMPONENT_CONFIG \N 4.23.2 \N \N 7901269232 +23.0.0-17258 keycloak META-INF/jpa-changelog-23.0.0.xml 2024-02-14 09:01:09.343484 119 EXECUTED 9:36506d679a83bbfda85a27ea1864dca8 addColumn tableName=EVENT_ENTITY \N 4.23.2 \N \N 7901269232 \. @@ -2385,9 +2379,9 @@ grafana a5bb3a5f-fd26-4be6-9557-26e20a03d33d f grafana d6ffe9fc-a03c-4496-85dc-dbb5e7754587 f grafana d6077ed7-b265-4f82-9336-24614967bd5d t grafana 699671ab-e7c1-4fcf-beb8-ea54f1471fc1 t -grafana c61f5b19-c17e-49a1-91b8-a0296411b928 f grafana d30340a8-630b-416e-8c93-3ccf932d34f3 t master a96603aa-e6db-4b3e-8baa-679c75ccfc8f t +grafana c61f5b19-c17e-49a1-91b8-a0296411b928 t \. @@ -2395,7 +2389,7 @@ master a96603aa-e6db-4b3e-8baa-679c75ccfc8f t -- Data for Name: event_entity; Type: TABLE DATA; Schema: public; Owner: keycloak -- -COPY public.event_entity (id, client_id, details_json, error, ip_address, realm_id, session_id, event_time, type, user_id) FROM stdin; +COPY public.event_entity (id, client_id, details_json, error, ip_address, realm_id, session_id, event_time, type, user_id, details_json_long_value) FROM stdin; \. @@ -2524,6 +2518,9 @@ COPY public.idp_mapper_config (idp_mapper_id, value, name) FROM stdin; -- COPY public.keycloak_group (id, name, parent_group, realm_id) FROM stdin; +f1975bf4-6e92-479a-923c-d7d5b65d684c First grafana +fe974984-8b18-4925-beef-37b6cfb6af7b Second grafana +4cc0bd0f-9071-42a9-b282-be22515156ba Third grafana \. @@ -2628,6 +2625,7 @@ c9a895d1-c901-46b0-91cf-2c67902b4a93 a5a8fed6-0bca-4646-9946-2fe84175353b t ${ro COPY public.migration_model (id, version, update_time) FROM stdin; g5slr 12.0.1 1643820448 wupxt 20.0.2 1673274863 +y2nke 23.0.1 1707901269 \. @@ -2710,13 +2708,13 @@ b4854867-3bfb-409b-92a8-6ec37db17f99 phone number verified openid-connect oidc-u 1fc8999a-04d9-421b-8557-e417a3750358 realm roles openid-connect oidc-usermodel-realm-role-mapper \N d6077ed7-b265-4f82-9336-24614967bd5d 384e97dd-36ad-4b0e-af63-d0cb3a2153d4 allowed web origins openid-connect oidc-allowed-origins-mapper \N 699671ab-e7c1-4fcf-beb8-ea54f1471fc1 f03cac68-3f0e-4068-9adf-ee64567689a7 upn openid-connect oidc-usermodel-property-mapper \N c61f5b19-c17e-49a1-91b8-a0296411b928 -04183ee1-b558-4f63-839f-922d30b34a9e groups openid-connect oidc-usermodel-realm-role-mapper \N c61f5b19-c17e-49a1-91b8-a0296411b928 df78645e-c32b-4160-b79f-42e622d71982 locale openid-connect oidc-usermodel-attribute-mapper 805aebc8-9d01-42b6-bcce-6ce48ca63ef0 \N 0108b99f-2f31-4e73-9597-cb29e0e8c486 username openid-connect oidc-usermodel-property-mapper \N f619a55a-d565-4cc0-8bf4-4dbaab5382fe 70b0a264-a7c3-43ff-b24f-14ca4f5f118e login openid-connect oidc-usermodel-property-mapper \N 0a7c7dde-23d7-4a93-bdee-4a8963aee9a4 2f8ee9af-b6dd-4790-9e7b-cce83a603566 name openid-connect oidc-full-name-mapper \N d4723cd4-f717-44b7-a9b0-6c32c5ecd23f 854a81a5-8e06-4257-98ec-0e3087356223 acr loa level openid-connect oidc-acr-mapper \N d30340a8-630b-416e-8c93-3ccf932d34f3 53832401-d27c-489e-801f-9807cdaa4b08 acr loa level openid-connect oidc-acr-mapper \N a96603aa-e6db-4b3e-8baa-679c75ccfc8f +6814ca6a-2d7d-495d-87ad-53e12b561808 groups openid-connect oidc-group-membership-mapper \N c61f5b19-c17e-49a1-91b8-a0296411b928 \. @@ -2991,12 +2989,6 @@ f03cac68-3f0e-4068-9adf-ee64567689a7 true id.token.claim f03cac68-3f0e-4068-9adf-ee64567689a7 true access.token.claim f03cac68-3f0e-4068-9adf-ee64567689a7 upn claim.name f03cac68-3f0e-4068-9adf-ee64567689a7 String jsonType.label -04183ee1-b558-4f63-839f-922d30b34a9e true multivalued -04183ee1-b558-4f63-839f-922d30b34a9e foo user.attribute -04183ee1-b558-4f63-839f-922d30b34a9e true id.token.claim -04183ee1-b558-4f63-839f-922d30b34a9e true access.token.claim -04183ee1-b558-4f63-839f-922d30b34a9e groups claim.name -04183ee1-b558-4f63-839f-922d30b34a9e String jsonType.label df78645e-c32b-4160-b79f-42e622d71982 true userinfo.token.claim df78645e-c32b-4160-b79f-42e622d71982 locale user.attribute df78645e-c32b-4160-b79f-42e622d71982 true id.token.claim @@ -3025,6 +3017,13 @@ df78645e-c32b-4160-b79f-42e622d71982 String jsonType.label 854a81a5-8e06-4257-98ec-0e3087356223 true access.token.claim 53832401-d27c-489e-801f-9807cdaa4b08 true id.token.claim 53832401-d27c-489e-801f-9807cdaa4b08 true access.token.claim +6814ca6a-2d7d-495d-87ad-53e12b561808 true introspection.token.claim +6814ca6a-2d7d-495d-87ad-53e12b561808 true userinfo.token.claim +6814ca6a-2d7d-495d-87ad-53e12b561808 true id.token.claim +6814ca6a-2d7d-495d-87ad-53e12b561808 true access.token.claim +6814ca6a-2d7d-495d-87ad-53e12b561808 groups claim.name +6814ca6a-2d7d-495d-87ad-53e12b561808 false full.path +6814ca6a-2d7d-495d-87ad-53e12b561808 true multivalued \. @@ -3199,16 +3198,16 @@ ad4dfd2c-307a-4563-b93a-0bb726b4ccaa VERIFY_EMAIL Verify Email master t f VERIFY 2c7fffa4-ff20-4015-9a97-cc6a19e698ba UPDATE_PROFILE Update Profile master t f UPDATE_PROFILE 40 c76d17f4-eacf-497a-ab5a-f78936bbc50e CONFIGURE_TOTP Configure OTP master t f CONFIGURE_TOTP 10 83de9f97-43df-4265-982c-5414a2b19985 UPDATE_PASSWORD Update Password master t f UPDATE_PASSWORD 30 -9f538737-770e-4731-abd9-e98172a85d2f terms_and_conditions Terms and Conditions master f f terms_and_conditions 20 306fc47e-d8ae-4bb1-b2bc-53608a44536c update_user_locale Update User Locale master t f update_user_locale 1000 f158f7d8-8b7f-414c-b1bd-0dde83c91133 delete_account Delete Account master f f delete_account 60 969a57d1-c906-4f49-87d6-3cbba2f3898a VERIFY_EMAIL Verify Email grafana t f VERIFY_EMAIL 50 233d5b8e-6f36-450f-bffd-43b82e27295c UPDATE_PROFILE Update Profile grafana t f UPDATE_PROFILE 40 ab3a9aa7-3d1b-4fb1-93ad-9412142deed3 CONFIGURE_TOTP Configure OTP grafana t f CONFIGURE_TOTP 10 988d8e0d-35ef-4e6a-8b48-821cca56acf2 UPDATE_PASSWORD Update Password grafana t f UPDATE_PASSWORD 30 -0e2b6144-5c2c-4dcb-92d8-00529b19a7a5 terms_and_conditions Terms and Conditions grafana f f terms_and_conditions 20 94993a02-f883-4f8a-a549-d48f95aabed2 update_user_locale Update User Locale grafana t f update_user_locale 1000 72d09b7f-acde-4b90-af9a-ea3c642a2f6d delete_account Delete Account grafana f f delete_account 60 +9f538737-770e-4731-abd9-e98172a85d2f TERMS_AND_CONDITIONS Terms and Conditions master f f TERMS_AND_CONDITIONS 20 +0e2b6144-5c2c-4dcb-92d8-00529b19a7a5 TERMS_AND_CONDITIONS Terms and Conditions grafana f f TERMS_AND_CONDITIONS 20 \. @@ -3386,6 +3385,11 @@ COPY public.user_federation_provider (id, changed_sync_period, display_name, ful -- COPY public.user_group_membership (group_id, user_id) FROM stdin; +f1975bf4-6e92-479a-923c-d7d5b65d684c 88692d07-bb9a-46cf-844c-7ff5c529cd04 +f1975bf4-6e92-479a-923c-d7d5b65d684c 8f58cbec-6e40-4bab-bff0-1c5ff899fe2e +fe974984-8b18-4925-beef-37b6cfb6af7b 88692d07-bb9a-46cf-844c-7ff5c529cd04 +4cc0bd0f-9071-42a9-b282-be22515156ba 6db3c5e5-b84b-4f9d-a7a8-8d05b03c929d +4cc0bd0f-9071-42a9-b282-be22515156ba 1a85b7e0-4baa-420b-89f8-1cea43a540dd \. diff --git a/package.json b/package.json index 982def9c4c5..4663cb91d56 100644 --- a/package.json +++ b/package.json @@ -183,7 +183,7 @@ "jest-matcher-utils": "29.7.0", "lerna": "8.1.2", "mini-css-extract-plugin": "2.8.0", - "msw": "1.3.2", + "msw": "2.2.0", "mutationobserver-shim": "0.3.7", "ngtemplate-loader": "2.1.0", "node-notifier": "10.0.1", diff --git a/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx b/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx index f0a5c8c5ecf..1c48a33992a 100644 --- a/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx +++ b/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx @@ -2,12 +2,30 @@ import { css, cx } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; -export const getDragStyles = (theme: GrafanaTheme2) => { +export type DragHandlePosition = 'middle' | 'start' | 'end'; + +export const getDragStyles = (theme: GrafanaTheme2, handlePosition?: DragHandlePosition) => { + const position = handlePosition || 'middle'; const baseColor = theme.colors.emphasize(theme.colors.background.secondary, 0.15); const hoverColor = theme.colors.primary.border; const clickTargetSize = theme.spacing(2); const handlebarThickness = 4; const handlebarWidth = 200; + let verticalOffset = '50%'; + let horizontalOffset = '50%'; + + switch (position) { + case 'start': { + verticalOffset = '0%'; + horizontalOffset = '0%'; + break; + } + case 'end': { + verticalOffset = '100%'; + horizontalOffset = '100%'; + break; + } + } const dragHandleBase = css({ position: 'relative', @@ -16,17 +34,17 @@ export const getDragStyles = (theme: GrafanaTheme2) => { content: '""', position: 'absolute', transition: theme.transitions.create('border-color'), + zIndex: 1, }, '&:after': { background: baseColor, content: '""', position: 'absolute', - left: '50%', - top: '50%', transition: theme.transitions.create('background'), transform: 'translate(-50%, -50%)', borderRadius: theme.shape.radius.pill, + zIndex: 1, }, '&:hover': { @@ -50,11 +68,13 @@ export const getDragStyles = (theme: GrafanaTheme2) => { '&:before': { borderRight: '1px solid transparent', height: '100%', - left: '50%', + left: verticalOffset, transform: 'translateX(-50%)', }, '&:after': { + left: verticalOffset, + top: '50%', height: handlebarWidth, width: handlebarThickness, }, @@ -68,12 +88,14 @@ export const getDragStyles = (theme: GrafanaTheme2) => { '&:before': { borderTop: '1px solid transparent', - top: '50%', + top: horizontalOffset, transform: 'translateY(-50%)', width: '100%', }, '&:after': { + left: '50%', + top: horizontalOffset, height: handlebarThickness, width: handlebarWidth, }, diff --git a/packages/grafana-ui/src/components/Splitter/Splitter.mdx b/packages/grafana-ui/src/components/Splitter/Splitter.mdx new file mode 100644 index 00000000000..af7d3fc015b --- /dev/null +++ b/packages/grafana-ui/src/components/Splitter/Splitter.mdx @@ -0,0 +1,23 @@ +import { Meta, Preview, ArgTypes } from '@storybook/blocks'; +import { Box, Splitter, Text } from '@grafana/ui'; + + + +# Splitter + +The splitter creates two resizable panes, either horizontally or vertically. + + +
+ + + Primary + + + Secondary + + +
+
+ + diff --git a/packages/grafana-ui/src/components/Splitter/Splitter.story.tsx b/packages/grafana-ui/src/components/Splitter/Splitter.story.tsx new file mode 100644 index 00000000000..7248f78f3d2 --- /dev/null +++ b/packages/grafana-ui/src/components/Splitter/Splitter.story.tsx @@ -0,0 +1,55 @@ +import { css } from '@emotion/css'; +import { Meta, StoryFn } from '@storybook/react'; +import React from 'react'; + +import { Splitter, useTheme2 } from '@grafana/ui'; + +import { DashboardStoryCanvas } from '../../utils/storybook/DashboardStoryCanvas'; + +import mdx from './Splitter.mdx'; + +const meta: Meta = { + title: 'General/Layout/Splitter', + component: Splitter, + parameters: { + docs: { + page: mdx, + }, + controls: { + exclude: [], + }, + }, + argTypes: { + initialSize: { control: { type: 'number', min: 0.1, max: 1 } }, + }, +}; + +export const Basic: StoryFn = (args) => { + const theme = useTheme2(); + const paneStyles = css({ + display: 'flex', + flexGrow: 1, + background: theme.colors.background.primary, + padding: theme.spacing(2), + border: `1px solid ${theme.colors.border.weak}`, + height: '100%', + }); + + return ( + +
+ +
Primary
+
Secondary
+
+
+
+ ); +}; + +Basic.args = { + direction: 'row', + dragPosition: 'middle', +}; + +export default meta; diff --git a/packages/grafana-ui/src/components/Splitter/Splitter.tsx b/packages/grafana-ui/src/components/Splitter/Splitter.tsx new file mode 100644 index 00000000000..aa4958a443b --- /dev/null +++ b/packages/grafana-ui/src/components/Splitter/Splitter.tsx @@ -0,0 +1,475 @@ +import { css } from '@emotion/css'; +import { clamp, throttle } from 'lodash'; +import React, { useCallback, useId, useLayoutEffect, useRef } from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; + +import { useStyles2 } from '../../themes'; +import { DragHandlePosition, getDragStyles } from '../DragHandle/DragHandle'; + +export interface Props { + /** + * The initial size of the primary pane between 0-1, defaults to 0.5 + */ + initialSize?: number; + direction?: 'row' | 'column'; + dragPosition?: DragHandlePosition; + primaryPaneStyles?: React.CSSProperties; + secondaryPaneStyles?: React.CSSProperties; + /** + * Called when ever the size of the primary pane changes + * @param size (float from 0-1) + */ + onSizeChange?: (size: number) => void; + children: [React.ReactNode, React.ReactNode]; +} + +/** + * Splits two children into two resizable panes + * @alpha + */ +export function Splitter(props: Props) { + const { + direction = 'row', + initialSize = 0.5, + primaryPaneStyles, + secondaryPaneStyles, + onSizeChange, + dragPosition = 'middle', + children, + } = props; + + const { containerRef, firstPaneRef, minDimProp, splitterProps, secondPaneRef } = useSplitter( + direction, + onSizeChange, + children + ); + + const kids = React.Children.toArray(children); + const styles = useStyles2(getStyles, direction); + const dragStyles = useStyles2(getDragStyles, dragPosition); + const dragHandleStyle = direction === 'column' ? dragStyles.dragHandleHorizontal : dragStyles.dragHandleVertical; + const id = useId(); + + const secondAvailable = kids.length === 2; + const visibilitySecond = secondAvailable ? 'visible' : 'hidden'; + let firstChildSize = initialSize; + + // If second child is missing let first child have all the space + if (!children[1]) { + firstChildSize = 1; + } + + return ( +
+
+ {kids[0]} +
+ + {kids[1] && ( + <> +
+ +
+ {kids[1]} +
+ + )} +
+ ); +} + +function getStyles(theme: GrafanaTheme2, direction: Props['direction']) { + return { + container: css({ + display: 'flex', + flexDirection: direction === 'row' ? 'row' : 'column', + width: '100%', + flexGrow: 1, + overflow: 'hidden', + }), + panel: css({ display: 'flex', position: 'relative', flexBasis: 0 }), + dragEdge: { + second: css({ + top: 0, + left: theme.spacing(-1), + bottom: 0, + position: 'absolute', + zIndex: theme.zIndex.modal, + }), + first: css({ + top: 0, + left: theme.spacing(-1), + bottom: 0, + position: 'absolute', + zIndex: theme.zIndex.modal, + }), + }, + }; +} + +const PIXELS_PER_MS = 0.3 as const; +const VERTICAL_KEYS = new Set(['ArrowUp', 'ArrowDown']); +const HORIZONTAL_KEYS = new Set(['ArrowLeft', 'ArrowRight']); + +const propsForDirection = { + row: { + dim: 'width', + axis: 'clientX', + min: 'minWidth', + max: 'maxWidth', + }, + column: { + dim: 'height', + axis: 'clientY', + min: 'minHeight', + max: 'maxHeight', + }, +} as const; + +function useSplitter(direction: 'row' | 'column', onSizeChange: Props['onSizeChange'], children: Props['children']) { + const handleSize = 16; + const splitterRef = useRef(null); + const firstPaneRef = useRef(null); + const secondPaneRef = useRef(null); + const containerRef = useRef(null); + const containerSize = useRef(null); + const primarySizeRef = useRef<'1fr' | number>('1fr'); + + const firstPaneMeasurements = useRef(undefined); + const savedPos = useRef(undefined); + + const measurementProp = propsForDirection[direction].dim; + const clientAxis = propsForDirection[direction].axis; + const minDimProp = propsForDirection[direction].min; + const maxDimProp = propsForDirection[direction].max; + + // Using a resize observer here, as with content or screen based width/height the ratio between panes might + // change after a window resize, so ariaValueNow needs to be updated accordingly + useResizeObserver( + containerRef.current!, + (entries) => { + for (const entry of entries) { + if (!entry.target.isSameNode(containerRef.current)) { + return; + } + + if (!firstPaneRef.current) { + return; + } + + const curSize = firstPaneRef.current!.getBoundingClientRect()[measurementProp]; + const newDims = measureElement(firstPaneRef.current); + + splitterRef.current!.ariaValueNow = `${clamp( + ((curSize - newDims[minDimProp]) / (newDims[maxDimProp] - newDims[minDimProp])) * 100, + 0, + 100 + )}`; + } + }, + 500, + [maxDimProp, minDimProp, direction, measurementProp] + ); + + const dragStart = useRef(null); + const onPointerDown = useCallback( + (e: React.PointerEvent) => { + if (!firstPaneRef.current) { + return; + } + + // measure left-side width + primarySizeRef.current = firstPaneRef.current!.getBoundingClientRect()[measurementProp]; + containerSize.current = containerRef.current!.getBoundingClientRect()[measurementProp]; + + // set position at start of drag + dragStart.current = e[clientAxis]; + splitterRef.current!.setPointerCapture(e.pointerId); + firstPaneMeasurements.current = measureElement(firstPaneRef.current); + + savedPos.current = undefined; + }, + [measurementProp, clientAxis] + ); + + const onPointerMove = useCallback( + (e: React.PointerEvent) => { + if (dragStart.current !== null && primarySizeRef.current !== '1fr') { + const diff = e[clientAxis] - dragStart.current; + const dims = firstPaneMeasurements.current!; + const newSize = clamp(primarySizeRef.current + diff, dims[minDimProp], dims[maxDimProp]); + const newFlex = newSize / (containerSize.current! - handleSize); + firstPaneRef.current!.style.flexGrow = `${newFlex}`; + secondPaneRef.current!.style.flexGrow = `${1 - newFlex}`; + const ariaValueNow = clamp( + ((newSize - dims[minDimProp]) / (dims[maxDimProp] - dims[minDimProp])) * 100, + 0, + 100 + ); + + splitterRef.current!.ariaValueNow = `${ariaValueNow}`; + } + }, + [handleSize, clientAxis, minDimProp, maxDimProp] + ); + + const onPointerUp = useCallback( + (e: React.PointerEvent) => { + e.preventDefault(); + e.stopPropagation(); + splitterRef.current!.releasePointerCapture(e.pointerId); + dragStart.current = null; + onSizeChange?.(parseFloat(firstPaneRef.current!.style.flexGrow)); + }, + [onSizeChange] + ); + + const pressedKeys = useRef(new Set()); + const keysLastHandledAt = useRef(null); + const handlePressedKeys = useCallback( + (time: number) => { + const nothingPressed = pressedKeys.current.size === 0; + if (nothingPressed) { + keysLastHandledAt.current = null; + return; + } else if (primarySizeRef.current === '1fr') { + return; + } + + const dt = time - (keysLastHandledAt.current ?? time); + const dx = dt * PIXELS_PER_MS; + let sizeChange = 0; + + if (direction === 'row') { + if (pressedKeys.current.has('ArrowLeft')) { + sizeChange -= dx; + } + if (pressedKeys.current.has('ArrowRight')) { + sizeChange += dx; + } + } else { + if (pressedKeys.current.has('ArrowUp')) { + sizeChange -= dx; + } + if (pressedKeys.current.has('ArrowDown')) { + sizeChange += dx; + } + } + + const firstPaneDims = firstPaneMeasurements.current!; + const curSize = firstPaneRef.current!.getBoundingClientRect()[measurementProp]; + const newSize = clamp(curSize + sizeChange, firstPaneDims[minDimProp], firstPaneDims[maxDimProp]); + + const newFlex = newSize / (containerSize.current! - handleSize); + + firstPaneRef.current!.style.flexGrow = `${newFlex}`; + secondPaneRef.current!.style.flexGrow = `${1 - newFlex}`; + const ariaValueNow = + ((newSize - firstPaneDims[minDimProp]) / (firstPaneDims[maxDimProp] - firstPaneDims[minDimProp])) * 100; + splitterRef.current!.ariaValueNow = `${clamp(ariaValueNow, 0, 100)}`; + + keysLastHandledAt.current = time; + window.requestAnimationFrame(handlePressedKeys); + }, + [direction, handleSize, minDimProp, maxDimProp, measurementProp] + ); + + const onKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (!firstPaneRef.current || !secondPaneRef.current || !splitterRef.current || !containerRef.current) { + return; + } + + if (e.key === 'Enter') { + if (savedPos.current === undefined) { + savedPos.current = firstPaneRef.current!.style.flexGrow; + firstPaneRef.current!.style.flexGrow = '0'; + secondPaneRef.current!.style.flexGrow = '1'; + } else { + firstPaneRef.current!.style.flexGrow = savedPos.current; + secondPaneRef.current!.style.flexGrow = `${1 - parseFloat(savedPos.current)}`; + savedPos.current = undefined; + } + return; + } else if (e.key === 'Home') { + firstPaneMeasurements.current = measureElement(firstPaneRef.current); + containerSize.current = containerRef.current!.getBoundingClientRect()[measurementProp]; + const newFlex = firstPaneMeasurements.current[minDimProp] / (containerSize.current - handleSize); + firstPaneRef.current.style.flexGrow = `${newFlex}`; + secondPaneRef.current.style.flexGrow = `${1 - newFlex}`; + splitterRef.current.ariaValueNow = '0'; + return; + } else if (e.key === 'End') { + firstPaneMeasurements.current = measureElement(firstPaneRef.current); + containerSize.current = containerRef.current!.getBoundingClientRect()[measurementProp]; + const newFlex = firstPaneMeasurements.current[maxDimProp] / (containerSize.current - handleSize); + firstPaneRef.current!.style.flexGrow = `${newFlex}`; + secondPaneRef.current!.style.flexGrow = `${1 - newFlex}`; + splitterRef.current!.ariaValueNow = '100'; + return; + } + + if ( + !( + (direction === 'column' && VERTICAL_KEYS.has(e.key)) || + (direction === 'row' && HORIZONTAL_KEYS.has(e.key)) + ) || + pressedKeys.current.has(e.key) + ) { + return; + } + + savedPos.current = undefined; + e.preventDefault(); + e.stopPropagation(); + primarySizeRef.current = firstPaneRef.current.getBoundingClientRect()[measurementProp]; + containerSize.current = containerRef.current!.getBoundingClientRect()[measurementProp]; + firstPaneMeasurements.current = measureElement(firstPaneRef.current); + const newKey = !pressedKeys.current.has(e.key); + + if (newKey) { + const initiateAnimationLoop = pressedKeys.current.size === 0; + pressedKeys.current.add(e.key); + + if (initiateAnimationLoop) { + window.requestAnimationFrame(handlePressedKeys); + } + } + }, + [direction, handlePressedKeys, handleSize, maxDimProp, measurementProp, minDimProp] + ); + + const onKeyUp = useCallback( + (e: React.KeyboardEvent) => { + if ( + (direction === 'row' && !HORIZONTAL_KEYS.has(e.key)) || + (direction === 'column' && !VERTICAL_KEYS.has(e.key)) + ) { + return; + } + + pressedKeys.current.delete(e.key); + onSizeChange?.(parseFloat(firstPaneRef.current!.style.flexGrow)); + }, + [direction, onSizeChange] + ); + + const onDoubleClick = useCallback(() => { + if (!firstPaneRef.current || !secondPaneRef.current) { + return; + } + + firstPaneRef.current.style.flexGrow = '0.5'; + secondPaneRef.current.style.flexGrow = '0.5'; + const dim = measureElement(firstPaneRef.current); + firstPaneMeasurements.current = dim; + primarySizeRef.current = firstPaneRef.current!.getBoundingClientRect()[measurementProp]; + splitterRef.current!.ariaValueNow = `${((primarySizeRef.current - dim[minDimProp]) / (dim[maxDimProp] - dim[minDimProp])) * 100}`; + }, [maxDimProp, measurementProp, minDimProp]); + + const onBlur = useCallback(() => { + // If focus is lost while keys are held, stop changing panel sizes + if (pressedKeys.current.size > 0) { + pressedKeys.current.clear(); + dragStart.current = null; + onSizeChange?.(parseFloat(firstPaneRef.current!.style.flexGrow)); + } + }, [onSizeChange]); + + return { + containerRef, + firstPaneRef, + minDimProp, + splitterProps: { + onPointerUp, + onPointerDown, + onPointerMove, + onKeyDown, + onKeyUp, + onDoubleClick, + onBlur, + ref: splitterRef, + style: { [measurementProp]: `${handleSize}px` }, + }, + secondPaneRef, + }; +} + +interface MeasureResult { + minWidth: number; + maxWidth: number; + minHeight: number; + maxHeight: number; +} + +function measureElement(ref: T): MeasureResult { + const savedBodyOverflow = document.body.style.overflow; + const savedWidth = ref.style.width; + const savedHeight = ref.style.height; + const savedFlex = ref.style.flexGrow; + document.body.style.overflow = 'hidden'; + ref.style.flexGrow = '0'; + const { width: minWidth, height: minHeight } = ref.getBoundingClientRect(); + + ref.style.flexGrow = '100'; + const { width: maxWidth, height: maxHeight } = ref.getBoundingClientRect(); + + document.body.style.overflow = savedBodyOverflow; + ref.style.width = savedWidth; + ref.style.height = savedHeight; + ref.style.flexGrow = savedFlex; + + return { minWidth, maxWidth, minHeight, maxHeight } as MeasureResult; +} + +function useResizeObserver( + target: Element, + cb: (entries: ResizeObserverEntry[]) => void, + throttleWait = 0, + deps?: React.DependencyList +) { + const throttledCallback = throttle(cb, throttleWait); + + useLayoutEffect(() => { + if (!target) { + return; + } + + const resizeObserver = new ResizeObserver(throttledCallback); + + resizeObserver.observe(target, { box: 'device-pixel-content-box' }); + return () => resizeObserver.disconnect(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, deps); +} diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 706175a2ee6..435d63f2442 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -265,6 +265,7 @@ export { Avatar } from './UsersIndicator/Avatar'; export { InlineFormLabel } from './FormLabel/FormLabel'; export { Divider } from './Divider/Divider'; export { getDragStyles } from './DragHandle/DragHandle'; +export { Splitter } from './Splitter/Splitter'; export { LayoutItemContext, type LayoutItemContextProps } from './Layout/LayoutItemContext'; diff --git a/pkg/plugins/manager/loader/finder/local_test.go b/pkg/plugins/manager/loader/finder/local_test.go index 8c46a9dfe00..738611a6abb 100644 --- a/pkg/plugins/manager/loader/finder/local_test.go +++ b/pkg/plugins/manager/loader/finder/local_test.go @@ -143,6 +143,7 @@ func TestFinder_Find(t *testing.T) { {Name: "img1", Path: "img/screenshot1.png"}, {Name: "img2", Path: "img/screenshot2.png"}, }, + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "3.x.x", @@ -176,40 +177,19 @@ func TestFinder_Find(t *testing.T) { { name: "Multiple plugin dirs", pluginDirs: []string{"../../testdata/duplicate-plugins", "../../testdata/invalid-v1-signature"}, - expectedBundles: []*plugins.FoundBundle{{ - Primary: plugins.FoundPlugin{ - JSONData: plugins.JSONData{ - ID: "test-app", - Type: plugins.TypeDataSource, - Name: "Parent", - Info: plugins.Info{ - Author: plugins.InfoLink{ - Name: "Grafana Labs", - URL: "http://grafana.com", - }, - Description: "Parent plugin", - Version: "1.0.0", - Updated: "2020-10-20", - }, - Dependencies: plugins.Dependencies{ - GrafanaVersion: "*", - Plugins: []plugins.Dependency{}, - }, - }, - FS: mustNewStaticFSForTests(t, filepath.Join(testData, "duplicate-plugins/nested")), - }, - Children: []*plugins.FoundPlugin{ - { + expectedBundles: []*plugins.FoundBundle{ + { + Primary: plugins.FoundPlugin{ JSONData: plugins.JSONData{ ID: "test-app", Type: plugins.TypeDataSource, - Name: "Child", + Name: "Parent", Info: plugins.Info{ Author: plugins.InfoLink{ Name: "Grafana Labs", URL: "http://grafana.com", }, - Description: "Child plugin", + Description: "Parent plugin", Version: "1.0.0", Updated: "2020-10-20", }, @@ -218,10 +198,32 @@ func TestFinder_Find(t *testing.T) { Plugins: []plugins.Dependency{}, }, }, - FS: mustNewStaticFSForTests(t, filepath.Join(testData, "duplicate-plugins/nested/nested")), + FS: mustNewStaticFSForTests(t, filepath.Join(testData, "duplicate-plugins/nested")), + }, + Children: []*plugins.FoundPlugin{ + { + JSONData: plugins.JSONData{ + ID: "test-app", + Type: plugins.TypeDataSource, + Name: "Child", + Info: plugins.Info{ + Author: plugins.InfoLink{ + Name: "Grafana Labs", + URL: "http://grafana.com", + }, + Description: "Child plugin", + Version: "1.0.0", + Updated: "2020-10-20", + }, + Dependencies: plugins.Dependencies{ + GrafanaVersion: "*", + Plugins: []plugins.Dependency{}, + }, + }, + FS: mustNewStaticFSForTests(t, filepath.Join(testData, "duplicate-plugins/nested/nested")), + }, }, }, - }, { Primary: plugins.FoundPlugin{ JSONData: plugins.JSONData{ diff --git a/pkg/plugins/manager/loader/loader_test.go b/pkg/plugins/manager/loader/loader_test.go index 111494e6227..77360a7fe24 100644 --- a/pkg/plugins/manager/loader/loader_test.go +++ b/pkg/plugins/manager/loader/loader_test.go @@ -154,7 +154,8 @@ func TestLoader_Load(t *testing.T) { Class: plugins.ClassBundled, }, }, - }, { + }, + { name: "Load plugin with symbolic links", class: plugins.ClassExternal, cfg: &config.Cfg{Features: featuremgmt.WithFeatures()}, @@ -183,8 +184,9 @@ func TestLoader_Load(t *testing.T) { {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"}, }, - Version: "1.0.0", - Updated: "2015-02-10", + Version: "1.0.0", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "3.x.x", @@ -212,7 +214,8 @@ func TestLoader_Load(t *testing.T) { Name: "Nginx Panel", Type: string(plugins.TypePanel), Role: org.RoleViewer, - Slug: "nginx-panel"}, + Slug: "nginx-panel", + }, { Name: "Nginx Datasource", Type: string(plugins.TypeDataSource), @@ -230,7 +233,8 @@ func TestLoader_Load(t *testing.T) { SignatureOrg: "Grafana Labs", }, }, - }, { + }, + { name: "Load an unsigned plugin (development)", class: plugins.ClassExternal, cfg: &config.Cfg{ @@ -383,7 +387,8 @@ func TestLoader_Load(t *testing.T) { Small: "public/img/icn-app.svg", Large: "public/img/icn-app.svg", }, - Updated: "2015-02-10", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaDependency: ">=8.0.0", diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index 0305cdf0aec..5553ad331a5 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -130,6 +130,7 @@ type Info struct { Screenshots []Screenshots `json:"screenshots"` Version string `json:"version"` Updated string `json:"updated"` + Keywords []string `json:"keywords"` } type InfoLink struct { diff --git a/pkg/plugins/plugins_test.go b/pkg/plugins/plugins_test.go index 96eef9f0b59..5554c86d184 100644 --- a/pkg/plugins/plugins_test.go +++ b/pkg/plugins/plugins_test.go @@ -49,7 +49,8 @@ func Test_ReadPluginJSON(t *testing.T) { {Path: "img/screenshot1.png", Name: "img1"}, {Path: "img/screenshot2.png", Name: "img2"}, }, - Updated: "2015-02-10", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: Dependencies{ GrafanaVersion: "3.x.x", @@ -107,7 +108,7 @@ func Test_ReadPluginJSON(t *testing.T) { pluginJSON: func(t *testing.T) io.ReadCloser { pJSON := `{ "id": "grafana-pyroscope-datasource", - "type": "datasource", + "type": "datasource", "aliasIDs": ["phlare"] }` return io.NopCloser(strings.NewReader(pJSON)) diff --git a/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware.go b/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware.go index f5c62396571..f8282cd27e5 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware.go +++ b/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware.go @@ -19,6 +19,7 @@ import ( const GrafanaRequestID = "X-Grafana-Request-Id" const GrafanaSignedRequestID = "X-Grafana-Signed-Request-Id" +const XRealIPHeader = "X-Real-Ip" const GrafanaInternalRequest = "X-Grafana-Internal-Request" // NewHostedGrafanaACHeaderMiddleware creates a new plugins.ClientMiddleware that will @@ -83,6 +84,7 @@ func (m *HostedGrafanaACHeaderMiddleware) applyGrafanaRequestIDHeader(ctx contex if reqCtx != nil && reqCtx.Req != nil { remoteAddress := web.RemoteAddr(reqCtx.Req) if remoteAddress != "" { + h.SetHTTPHeader(XRealIPHeader, remoteAddress) return } } diff --git a/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware_test.go b/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware_test.go index 4ef2ef76d83..8204c70d4af 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware_test.go +++ b/pkg/services/pluginsintegration/clientmiddleware/grafana_request_id_header_middleware_test.go @@ -54,6 +54,9 @@ func Test_HostedGrafanaACHeaderMiddleware(t *testing.T) { require.Equal(t, cdt.CallResourceReq.Headers[GrafanaSignedRequestID][0], computed) + require.Len(t, cdt.CallResourceReq.Headers[XRealIPHeader], 1) + require.Equal(t, cdt.CallResourceReq.Headers[XRealIPHeader][0], "1.2.3.4") + // Internal header should not be set require.Len(t, cdt.CallResourceReq.Headers[GrafanaInternalRequest], 0) }) diff --git a/pkg/services/pluginsintegration/loader/loader_test.go b/pkg/services/pluginsintegration/loader/loader_test.go index c2b605716d8..1b3b75b53b5 100644 --- a/pkg/services/pluginsintegration/loader/loader_test.go +++ b/pkg/services/pluginsintegration/loader/loader_test.go @@ -154,7 +154,8 @@ func TestLoader_Load(t *testing.T) { Class: plugins.ClassBundled, }, }, - }, { + }, + { name: "Load plugin with symbolic links", class: plugins.ClassExternal, cfg: &config.Cfg{Features: featuremgmt.WithFeatures()}, @@ -183,8 +184,9 @@ func TestLoader_Load(t *testing.T) { {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"}, }, - Version: "1.0.0", - Updated: "2015-02-10", + Version: "1.0.0", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "3.x.x", @@ -212,7 +214,8 @@ func TestLoader_Load(t *testing.T) { Name: "Nginx Panel", Type: string(plugins.TypePanel), Role: org.RoleViewer, - Slug: "nginx-panel"}, + Slug: "nginx-panel", + }, { Name: "Nginx Datasource", Type: string(plugins.TypeDataSource), @@ -230,7 +233,8 @@ func TestLoader_Load(t *testing.T) { SignatureOrg: "Grafana Labs", }, }, - }, { + }, + { name: "Load an unsigned plugin (development)", class: plugins.ClassExternal, cfg: &config.Cfg{ @@ -269,7 +273,8 @@ func TestLoader_Load(t *testing.T) { Signature: "unsigned", }, }, - }, { + }, + { name: "Load an unsigned plugin (production)", class: plugins.ClassExternal, cfg: &config.Cfg{Features: featuremgmt.WithFeatures()}, @@ -392,38 +397,40 @@ func TestLoader_Load(t *testing.T) { }, pluginPaths: []string{filepath.Join(testDataDir(t), "test-app-with-includes")}, want: []*plugins.Plugin{ - {JSONData: plugins.JSONData{ - ID: "test-app", - Type: plugins.TypeApp, - Name: "Test App", - Info: plugins.Info{ - Author: plugins.InfoLink{ - Name: "Test Inc.", - URL: "http://test.com", + { + JSONData: plugins.JSONData{ + ID: "test-app", + Type: plugins.TypeApp, + Name: "Test App", + Info: plugins.Info{ + Author: plugins.InfoLink{ + Name: "Test Inc.", + URL: "http://test.com", + }, + Description: "Official Grafana Test App & Dashboard bundle", + Version: "1.0.0", + Links: []plugins.InfoLink{ + {Name: "Project site", URL: "http://project.com"}, + {Name: "License & Terms", URL: "http://license.com"}, + }, + Logos: plugins.Logos{ + Small: "public/img/icn-app.svg", + Large: "public/img/icn-app.svg", + }, + Updated: "2015-02-10", + Keywords: []string{"test"}, }, - Description: "Official Grafana Test App & Dashboard bundle", - Version: "1.0.0", - Links: []plugins.InfoLink{ - {Name: "Project site", URL: "http://project.com"}, - {Name: "License & Terms", URL: "http://license.com"}, + Dependencies: plugins.Dependencies{ + GrafanaDependency: ">=8.0.0", + GrafanaVersion: "*", + Plugins: []plugins.Dependency{}, }, - Logos: plugins.Logos{ - Small: "public/img/icn-app.svg", - Large: "public/img/icn-app.svg", + Includes: []*plugins.Includes{ + {Name: "Nginx Memory", Path: "dashboards/memory.json", Type: "dashboard", Role: org.RoleViewer, Slug: "nginx-memory"}, + {Name: "Root Page (react)", Type: "page", Role: org.RoleViewer, Path: "/a/my-simple-app", DefaultNav: true, AddToNav: true, Slug: "root-page-react"}, }, - Updated: "2015-02-10", + Backend: false, }, - Dependencies: plugins.Dependencies{ - GrafanaDependency: ">=8.0.0", - GrafanaVersion: "*", - Plugins: []plugins.Dependency{}, - }, - Includes: []*plugins.Includes{ - {Name: "Nginx Memory", Path: "dashboards/memory.json", Type: "dashboard", Role: org.RoleViewer, Slug: "nginx-memory"}, - {Name: "Root Page (react)", Type: "page", Role: org.RoleViewer, Path: "/a/my-simple-app", DefaultNav: true, AddToNav: true, Slug: "root-page-react"}, - }, - Backend: false, - }, DefaultNavURL: "/plugins/test-app/page/root-page-react", FS: mustNewStaticFSForTests(t, filepath.Join(testDataDir(t), "test-app-with-includes")), Class: plugins.ClassExternal, @@ -570,10 +577,12 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) { backendFactoryProvider.BackendFactoryFunc = func(ctx context.Context, plugin *plugins.Plugin) backendplugin.PluginFactoryFunc { return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) { require.Equal(t, "grafana-test-datasource", pluginID) - require.Equal(t, []string{"GF_VERSION=", "GF_EDITION=", "GF_ENTERPRISE_LICENSE_PATH=", + require.Equal(t, []string{ + "GF_VERSION=", "GF_EDITION=", "GF_ENTERPRISE_LICENSE_PATH=", "GF_ENTERPRISE_APP_URL=", "GF_ENTERPRISE_LICENSE_TEXT=", "GF_APP_URL=", "GF_PLUGIN_APP_CLIENT_ID=client-id", "GF_PLUGIN_APP_CLIENT_SECRET=secretz", - "GF_PLUGIN_APP_PRIVATE_KEY=priv@t3", "GF_INSTANCE_FEATURE_TOGGLES_ENABLE=externalServiceAuth"}, env()) + "GF_PLUGIN_APP_PRIVATE_KEY=priv@t3", "GF_INSTANCE_FEATURE_TOGGLES_ENABLE=externalServiceAuth", + }, env()) return &fakes.FakeBackendPlugin{}, nil } } @@ -614,38 +623,39 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) { } pluginPaths := []string{filepath.Join(testDataDir(t), "external-registration")} expected := []*plugins.Plugin{ - {JSONData: plugins.JSONData{ - ID: "grafana-test-datasource", - Type: plugins.TypeDataSource, - Name: "Test", - Backend: true, - Executable: "gpx_test_datasource", - Info: plugins.Info{ - Author: plugins.InfoLink{ - Name: "Grafana Labs", - URL: "https://grafana.com", + { + JSONData: plugins.JSONData{ + ID: "grafana-test-datasource", + Type: plugins.TypeDataSource, + Name: "Test", + Backend: true, + Executable: "gpx_test_datasource", + Info: plugins.Info{ + Author: plugins.InfoLink{ + Name: "Grafana Labs", + URL: "https://grafana.com", + }, + Version: "1.0.0", + Logos: plugins.Logos{ + Small: "public/plugins/grafana-test-datasource/img/ds.svg", + Large: "public/plugins/grafana-test-datasource/img/ds.svg", + }, + Updated: "2023-08-03", + Screenshots: []plugins.Screenshots{}, }, - Version: "1.0.0", - Logos: plugins.Logos{ - Small: "public/plugins/grafana-test-datasource/img/ds.svg", - Large: "public/plugins/grafana-test-datasource/img/ds.svg", + Dependencies: plugins.Dependencies{ + GrafanaVersion: "*", + Plugins: []plugins.Dependency{}, }, - Updated: "2023-08-03", - Screenshots: []plugins.Screenshots{}, - }, - Dependencies: plugins.Dependencies{ - GrafanaVersion: "*", - Plugins: []plugins.Dependency{}, - }, - IAM: &plugindef.IAM{ - Permissions: []plugindef.Permission{ - { - Action: "read", - Scope: stringPtr("datasource"), + IAM: &plugindef.IAM{ + Permissions: []plugindef.Permission{ + { + Action: "read", + Scope: stringPtr("datasource"), + }, }, }, }, - }, FS: mustNewStaticFSForTests(t, pluginPaths[0]), Class: plugins.ClassExternal, Signature: plugins.SignatureStatusUnsigned, @@ -662,10 +672,12 @@ func TestLoader_Load_ExternalRegistration(t *testing.T) { backendFactoryProvider.BackendFactoryFunc = func(ctx context.Context, plugin *plugins.Plugin) backendplugin.PluginFactoryFunc { return func(pluginID string, logger log.Logger, env func() []string) (backendplugin.Plugin, error) { require.Equal(t, "grafana-test-datasource", pluginID) - require.Equal(t, []string{"GF_VERSION=", "GF_EDITION=", "GF_ENTERPRISE_LICENSE_PATH=", + require.Equal(t, []string{ + "GF_VERSION=", "GF_EDITION=", "GF_ENTERPRISE_LICENSE_PATH=", "GF_ENTERPRISE_APP_URL=", "GF_ENTERPRISE_LICENSE_TEXT=", "GF_APP_URL=", "GF_PLUGIN_APP_CLIENT_ID=client-id", "GF_PLUGIN_APP_CLIENT_SECRET=secretz", - "GF_INSTANCE_FEATURE_TOGGLES_ENABLE=externalServiceAuth"}, env()) + "GF_INSTANCE_FEATURE_TOGGLES_ENABLE=externalServiceAuth", + }, env()) return &fakes.FakeBackendPlugin{}, nil } } @@ -906,7 +918,8 @@ func TestLoader_Load_RBACReady(t *testing.T) { Small: "public/img/icn-app.svg", Large: "public/img/icn-app.svg", }, - Updated: "2015-02-10", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "*", @@ -1049,7 +1062,8 @@ func TestLoader_Load_DuplicatePlugins(t *testing.T) { {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"}, }, - Updated: "2015-02-10", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "3.x.x", @@ -1129,7 +1143,8 @@ func TestLoader_Load_SkipUninitializedPlugins(t *testing.T) { {Path: "public/plugins/test-app/img/screenshot1.png", Name: "img1"}, {Path: "public/plugins/test-app/img/screenshot2.png", Name: "img2"}, }, - Updated: "2015-02-10", + Updated: "2015-02-10", + Keywords: []string{"test"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "3.x.x", @@ -1476,6 +1491,7 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { Description: "Grafana App Plugin Template", Version: "", Updated: "", + Keywords: []string{"panel", "template"}, }, Dependencies: plugins.Dependencies{ GrafanaVersion: "7.0.0", @@ -1556,6 +1572,7 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { Description: "Grafana Panel Plugin Template", Version: "", Updated: "", + Keywords: []string{"panel", "template"}, }, Dependencies: plugins.Dependencies{ GrafanaDependency: ">=7.0.0", @@ -1612,7 +1629,8 @@ type loaderDepOpts struct { } func newLoader(t *testing.T, cfg *config.Cfg, reg registry.Service, proc process.Manager, - backendFactory plugins.BackendFactoryProvider, sigErrTracker pluginerrs.SignatureErrorTracker) *Loader { + backendFactory plugins.BackendFactoryProvider, sigErrTracker pluginerrs.SignatureErrorTracker, +) *Loader { assets := assetpath.ProvideService(cfg, pluginscdn.ProvideService(cfg)) lic := fakes.NewFakeLicensingService() angularInspector := angularinspector.NewStaticInspector() @@ -1662,7 +1680,8 @@ func newLoaderWithOpts(t *testing.T, cfg *config.Cfg, opts loaderDepOpts) *Loade } func verifyState(t *testing.T, ps []*plugins.Plugin, reg registry.Service, - procPrvdr *fakes.FakeBackendProcessProvider, procMngr *fakes.FakeProcessManager) { + procPrvdr *fakes.FakeBackendProcessProvider, procMngr *fakes.FakeProcessManager, +) { t.Helper() for _, p := range ps { diff --git a/pkg/tests/api/plugins/data/expectedListResp.json b/pkg/tests/api/plugins/data/expectedListResp.json index 95d7dc9e65c..23702ab914f 100644 --- a/pkg/tests/api/plugins/data/expectedListResp.json +++ b/pkg/tests/api/plugins/data/expectedListResp.json @@ -19,7 +19,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -61,7 +62,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -98,7 +100,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -157,7 +160,14 @@ } ], "version": "", - "updated": "" + "updated": "", + "keywords": [ + "azure", + "monitor", + "Application Insights", + "Log Analytics", + "App Insights" + ] }, "dependencies": { "grafanaDependency": "\u003e=10.3.0", @@ -194,7 +204,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -231,7 +242,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -268,7 +280,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -305,7 +318,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -342,7 +356,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -379,7 +394,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -416,7 +432,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -458,7 +475,10 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": [ + "elasticsearch" + ] }, "dependencies": { "grafanaDependency": "", @@ -495,7 +515,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -532,7 +553,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -569,7 +591,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -606,7 +629,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -643,7 +667,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -685,7 +710,16 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": [ + "grafana", + "datasource", + "phlare", + "flamegraph", + "profiling", + "continuous profiling", + "pyroscope" + ] }, "dependencies": { "grafanaDependency": "\u003e=10.3.0-0", @@ -722,7 +756,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -768,7 +803,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -805,7 +841,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -842,7 +879,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -879,7 +917,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -925,7 +964,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -962,7 +1002,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1008,7 +1049,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1045,7 +1087,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1082,7 +1125,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1119,7 +1163,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1156,7 +1201,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1193,7 +1239,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1235,7 +1282,13 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": [ + "grafana", + "datasource", + "parca", + "profiling" + ] }, "dependencies": { "grafanaDependency": "\u003e=10.3.0-0", @@ -1272,7 +1325,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1309,7 +1363,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1351,7 +1406,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1388,7 +1444,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1425,7 +1482,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1462,7 +1520,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1499,7 +1558,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1536,7 +1596,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1578,7 +1639,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "\u003e=10.3.0-0", @@ -1615,7 +1677,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "\u003e=10.3.0-0", @@ -1652,7 +1715,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1689,7 +1753,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1726,7 +1791,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1763,7 +1829,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1800,7 +1867,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1837,7 +1905,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", @@ -1879,7 +1948,8 @@ "build": {}, "screenshots": null, "version": "", - "updated": "" + "updated": "", + "keywords": null }, "dependencies": { "grafanaDependency": "", diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres.go b/pkg/tsdb/grafana-postgresql-datasource/postgres.go index e66989879e5..84f26ab00f1 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres.go @@ -13,7 +13,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" "github.com/lib/pq" @@ -21,7 +20,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" ) func ProvideService(cfg *setting.Cfg) *Service { @@ -57,23 +55,28 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) return dsInfo.QueryData(ctx, req) } -func newPostgres(cfg *setting.Cfg, dsInfo sqleng.DataSourceInfo, cnnstr string, logger log.Logger, settings backend.DataSourceInstanceSettings) (*sql.DB, *sqleng.DataSourceHandler, error) { +func newPostgres(ctx context.Context, cfg *setting.Cfg, dsInfo sqleng.DataSourceInfo, cnnstr string, logger log.Logger, settings backend.DataSourceInstanceSettings) (*sql.DB, *sqleng.DataSourceHandler, error) { connector, err := pq.NewConnector(cnnstr) if err != nil { logger.Error("postgres connector creation failed", "error", err) return nil, nil, fmt.Errorf("postgres connector creation failed") } - // use the proxy-dialer if the secure socks proxy is enabled - proxyOpts := proxyutil.GetSQLProxyOptions(cfg.SecureSocksDSProxy, dsInfo, settings.Name, settings.Type) - if sdkproxy.New(proxyOpts).SecureSocksProxyEnabled() { - dialer, err := newPostgresProxyDialer(proxyOpts) + proxyClient, err := settings.ProxyClient(ctx) + if err != nil { + logger.Error("postgres proxy creation failed", "error", err) + return nil, nil, fmt.Errorf("postgres proxy creation failed") + } + + if proxyClient.SecureSocksProxyEnabled() { + dialer, err := proxyClient.NewSecureSocksProxyContextDialer() if err != nil { logger.Error("postgres proxy creation failed", "error", err) return nil, nil, fmt.Errorf("postgres proxy creation failed") } + postgresDialer := newPostgresProxyDialer(dialer) // update the postgres dialer with the proxy dialer - connector.Dialer(dialer) + connector.Dialer(postgresDialer) } config := sqleng.DataPluginConfiguration{ @@ -103,7 +106,7 @@ func newPostgres(cfg *setting.Cfg, dsInfo sqleng.DataSourceInfo, cnnstr string, func (s *Service) newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFactoryFunc { logger := s.logger - return func(_ context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { + return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { logger.Debug("Creating Postgres query endpoint") jsonData := sqleng.JsonData{ MaxOpenConns: cfg.SqlDatasourceMaxOpenConnsDefault, @@ -140,7 +143,7 @@ func (s *Service) newInstanceSettings(cfg *setting.Cfg) datasource.InstanceFacto return nil, err } - _, handler, err := newPostgres(cfg, dsInfo, cnnstr, logger, settings) + _, handler, err := newPostgres(ctx, cfg, dsInfo, cnnstr, logger, settings) if err != nil { logger.Error("Failed connecting to Postgres", "err", err) diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go index e066e189f3d..e217763600f 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go @@ -164,7 +164,7 @@ func TestIntegrationPostgresSnapshots(t *testing.T) { cnnstr := getCnnStr() - db, handler, err := newPostgres(cfg, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) + db, handler, err := newPostgres(context.Background(), cfg, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) t.Cleanup((func() { _, err := db.Exec("DROP TABLE tbl") diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go index 4262eccf323..f41f7f3c8a7 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go @@ -212,7 +212,7 @@ func TestIntegrationPostgres(t *testing.T) { cnnstr := postgresTestDBConnString() - db, exe, err := newPostgres(cfg, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) + db, exe, err := newPostgres(context.Background(), cfg, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) require.NoError(t, err) @@ -1268,7 +1268,7 @@ func TestIntegrationPostgres(t *testing.T) { dsInfo := sqleng.DataSourceInfo{} conf := setting.NewCfg() conf.DataProxyRowLimit = 1 - _, handler, err := newPostgres(conf, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) + _, handler, err := newPostgres(context.Background(), conf, dsInfo, cnnstr, logger, backend.DataSourceInstanceSettings{}) require.NoError(t, err) diff --git a/pkg/tsdb/grafana-postgresql-datasource/proxy.go b/pkg/tsdb/grafana-postgresql-datasource/proxy.go index 48a987c00c2..d06d8b68152 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/proxy.go +++ b/pkg/tsdb/grafana-postgresql-datasource/proxy.go @@ -5,21 +5,13 @@ import ( "net" "time" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/lib/pq" "golang.org/x/net/proxy" ) -// newPostgresProxyDriver updates the dialer for a postgres connector with a dialer that proxies connections through the secure socks proxy -// and returns a new postgres driver to register -func newPostgresProxyDialer(opts *sdkproxy.Options) (pq.Dialer, error) { - dialer, err := sdkproxy.New(opts).NewSecureSocksProxyContextDialer() - if err != nil { - return nil, err - } - - // update the postgres dialer with the proxy dialer - return &postgresProxyDialer{d: dialer}, nil +// we wrap the proxy.Dialer to become dialer that the postgres module accepts +func newPostgresProxyDialer(dialer proxy.Dialer) pq.Dialer { + return &postgresProxyDialer{d: dialer} } var _ pq.Dialer = (&postgresProxyDialer{}) diff --git a/pkg/tsdb/grafana-postgresql-datasource/proxy_test.go b/pkg/tsdb/grafana-postgresql-datasource/proxy_test.go index 3d12be8da1c..ec36e1a1eae 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/proxy_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/proxy_test.go @@ -3,40 +3,37 @@ package postgres import ( "database/sql" "fmt" + "net" "testing" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" "github.com/lib/pq" "github.com/stretchr/testify/require" + "golang.org/x/net/proxy" ) +type testDialer struct { +} + +func (d *testDialer) Dial(network, addr string) (c net.Conn, err error) { + return nil, fmt.Errorf("test-dialer is not functional") +} + +var _ proxy.Dialer = (&testDialer{}) + func TestPostgresProxyDriver(t *testing.T) { - settings := proxyutil.SetupTestSecureSocksProxySettings(t) - proxySettings := setting.SecureSocksDSProxySettings{ - Enabled: true, - ClientCert: settings.ClientCert, - ClientKey: settings.ClientKey, - RootCA: settings.RootCA, - ProxyAddress: settings.ProxyAddress, - ServerName: settings.ServerName, - } - opts := proxyutil.GetSQLProxyOptions(proxySettings, sqleng.DataSourceInfo{UID: "1", JsonData: sqleng.JsonData{SecureDSProxy: true}}, "pg", "postgres") dbURL := "localhost:5432" cnnstr := fmt.Sprintf("postgres://auser:password@%s/db?sslmode=disable", dbURL) t.Run("Connector should use dialer context that routes through the socks proxy to db", func(t *testing.T) { connector, err := pq.NewConnector(cnnstr) require.NoError(t, err) - dialer, err := newPostgresProxyDialer(opts) - require.NoError(t, err) + dialer := newPostgresProxyDialer(&testDialer{}) connector.Dialer(dialer) db := sql.OpenDB(connector) err = db.Ping() - require.Contains(t, err.Error(), fmt.Sprintf("socks connect %s %s->%s", "tcp", settings.ProxyAddress, dbURL)) + require.Contains(t, err.Error(), "test-dialer is not functional") }) } diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 9de5c50cef2..91ed62cd2b8 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -18,7 +18,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" @@ -26,7 +25,6 @@ import ( "github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" ) const ( @@ -89,12 +87,20 @@ func newInstanceSettings(cfg *setting.Cfg, logger log.Logger) datasource.Instanc protocol = "unix" } + proxyClient, err := settings.ProxyClient(ctx) + if err != nil { + return nil, err + } + // register the secure socks proxy dialer context, if enabled - proxyOpts := proxyutil.GetSQLProxyOptions(cfg.SecureSocksDSProxy, dsInfo, settings.Name, settings.Type) - if sdkproxy.New(proxyOpts).SecureSocksProxyEnabled() { + if proxyClient.SecureSocksProxyEnabled() { + dialer, err := proxyClient.NewSecureSocksProxyContextDialer() + if err != nil { + return nil, err + } // UID is only unique per org, the only way to ensure uniqueness is to do it by connection information uniqueIdentifier := dsInfo.User + dsInfo.DecryptedSecureJSONData["password"] + dsInfo.URL + dsInfo.Database - protocol, err = registerProxyDialerContext(protocol, uniqueIdentifier, proxyOpts) + protocol, err = registerProxyDialerContext(protocol, uniqueIdentifier, dialer) if err != nil { return nil, err } diff --git a/pkg/tsdb/mysql/proxy.go b/pkg/tsdb/mysql/proxy.go index c2103734c64..c2b288ba507 100644 --- a/pkg/tsdb/mysql/proxy.go +++ b/pkg/tsdb/mysql/proxy.go @@ -7,15 +7,14 @@ import ( "net" "github.com/go-sql-driver/mysql" - sdkproxy "github.com/grafana/grafana-plugin-sdk-go/backend/proxy" "golang.org/x/net/proxy" ) // registerProxyDialerContext registers a new dialer context to be used by mysql when the proxy network is // specified in the connection string -func registerProxyDialerContext(protocol, cnnstr string, opts *sdkproxy.Options) (string, error) { - // the dialer contains the true network used behind the scenes - dialer, err := getProxyDialerContext(protocol, opts) +func registerProxyDialerContext(protocol, cnnstr string, dialer proxy.Dialer) (string, error) { + // the mysqlDialer contains the true network used behind the scenes + mysqlDialer, err := getProxyDialerContext(protocol, dialer) if err != nil { return "", err } @@ -24,7 +23,7 @@ func registerProxyDialerContext(protocol, cnnstr string, opts *sdkproxy.Options) // have a unique network per connection string hash := fmt.Sprintf("%x", md5.Sum([]byte(cnnstr))) network := "proxy-" + hash - mysql.RegisterDialContext(network, dialer.DialContext) + mysql.RegisterDialContext(network, mysqlDialer.DialContext) return network, nil } @@ -36,14 +35,10 @@ type mySQLContextDialer struct { } // getProxyDialerContext returns a context dialer that will send the request through to the secure socks proxy -func getProxyDialerContext(actualNetwork string, opts *sdkproxy.Options) (*mySQLContextDialer, error) { - dialer, err := sdkproxy.New(opts).NewSecureSocksProxyContextDialer() - if err != nil { - return nil, err - } +func getProxyDialerContext(actualNetwork string, dialer proxy.Dialer) (*mySQLContextDialer, error) { contextDialer, ok := dialer.(proxy.ContextDialer) if !ok { - return nil, err + return nil, fmt.Errorf("mysql proxy creation failed") } return &mySQLContextDialer{dialer: contextDialer, network: actualNetwork}, nil } diff --git a/pkg/tsdb/mysql/proxy_test.go b/pkg/tsdb/mysql/proxy_test.go index 87ed82aa4f2..bc8b28799b7 100644 --- a/pkg/tsdb/mysql/proxy_test.go +++ b/pkg/tsdb/mysql/proxy_test.go @@ -3,29 +3,32 @@ package mysql import ( "context" "fmt" + "net" "testing" "github.com/go-sql-driver/mysql" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" - "github.com/grafana/grafana/pkg/tsdb/sqleng/proxyutil" "github.com/stretchr/testify/require" + "golang.org/x/net/proxy" ) +type testDialer struct { +} + +func (d *testDialer) Dial(network, addr string) (c net.Conn, err error) { + return nil, fmt.Errorf("test-dialer: Dial is not functional") +} + +func (d *testDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return nil, fmt.Errorf("test-dialer: DialContext is not functional") +} + +var _ proxy.Dialer = (&testDialer{}) +var _ proxy.ContextDialer = (&testDialer{}) + func TestMySQLProxyDialer(t *testing.T) { - settings := proxyutil.SetupTestSecureSocksProxySettings(t) - proxySettings := setting.SecureSocksDSProxySettings{ - Enabled: true, - ClientCert: settings.ClientCert, - ClientKey: settings.ClientKey, - RootCA: settings.RootCA, - ProxyAddress: settings.ProxyAddress, - ServerName: settings.ServerName, - } protocol := "tcp" - opts := proxyutil.GetSQLProxyOptions(proxySettings, sqleng.DataSourceInfo{UID: "1", JsonData: sqleng.JsonData{SecureDSProxy: true}}, "mysql", "mysql") dbURL := "localhost:5432" - network, err := registerProxyDialerContext(protocol, dbURL, opts) + network, err := registerProxyDialerContext(protocol, dbURL, &testDialer{}) require.NoError(t, err) driver := mysql.MySQLDriver{} cnnstr := fmt.Sprintf("test:test@%s(%s)/db", @@ -38,7 +41,7 @@ func TestMySQLProxyDialer(t *testing.T) { }) t.Run("Multiple networks can be created", func(t *testing.T) { - network, err := registerProxyDialerContext(protocol, dbURL, opts) + network, err := registerProxyDialerContext(protocol, dbURL, &testDialer{}) require.NoError(t, err) cnnstr2 := fmt.Sprintf("test:test@%s(%s)/db", network, @@ -56,6 +59,6 @@ func TestMySQLProxyDialer(t *testing.T) { require.NoError(t, err) _, err = conn.Connect(context.Background()) require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("socks connect %s %s->%s", protocol, settings.ProxyAddress, dbURL)) + require.Contains(t, err.Error(), "test-dialer: DialContext is not functional") }) } diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx index f5ed2595d83..73368d51752 100644 --- a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx +++ b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx @@ -1,7 +1,7 @@ import 'whatwg-fetch'; // fetch polyfill import { fireEvent, render as rtlRender, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; import React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; @@ -47,14 +47,11 @@ describe('NestedFolderPicker', () => { beforeAll(() => { window.HTMLElement.prototype.scrollIntoView = function () {}; server = setupServer( - rest.get('/api/folders/:uid', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - title: folderA.item.title, - uid: folderA.item.uid, - }) - ); + http.get('/api/folders/:uid', () => { + return HttpResponse.json({ + title: folderA.item.title, + uid: folderA.item.uid, + }); }) ); server.listen(); diff --git a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx index b14798e4f35..747f66b4eb1 100644 --- a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx +++ b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx @@ -1,3 +1,4 @@ +import 'whatwg-fetch'; import { render, waitFor, waitForElementToBeRemoved, within } from '@testing-library/react'; import { setupServer } from 'msw/node'; import React from 'react'; @@ -11,7 +12,6 @@ import { backendSrv } from 'app/core/services/backend_srv'; import { DashboardSearchItem, DashboardSearchItemType } from 'app/features/search/types'; import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types'; import { RuleWithLocation } from 'app/types/unified-alerting'; -import 'whatwg-fetch'; import { RulerAlertingRuleDTO, diff --git a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx index 31fe270eaff..92583016959 100644 --- a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx +++ b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx @@ -1,10 +1,9 @@ -import { render, screen } from '@testing-library/react'; +import 'whatwg-fetch'; +import { render, screen, waitFor } from '@testing-library/react'; import { setupServer } from 'msw/node'; import React from 'react'; import { Provider } from 'react-redux'; -import 'whatwg-fetch'; - import { setBackendSrv } from '@grafana/runtime'; import { backendSrv } from 'app/core/services/backend_srv'; import { configureStore } from 'app/store/configureStore'; @@ -76,7 +75,9 @@ describe('GrafanaAlertmanagerDeliveryWarning', () => { ); - expect(container).toBeEmptyDOMElement(); + await waitFor(() => { + expect(container).toBeEmptyDOMElement(); + }); }); it('Should render no warning when choice is All but no active AM instances', async () => { @@ -89,7 +90,9 @@ describe('GrafanaAlertmanagerDeliveryWarning', () => { ); - expect(container).toBeEmptyDOMElement(); + await waitFor(() => { + expect(container).toBeEmptyDOMElement(); + }); }); }); diff --git a/public/app/features/alerting/unified/components/PluginBridge.mock.ts b/public/app/features/alerting/unified/components/PluginBridge.mock.ts index 3644ce5779a..d71d70c313d 100644 --- a/public/app/features/alerting/unified/components/PluginBridge.mock.ts +++ b/public/app/features/alerting/unified/components/PluginBridge.mock.ts @@ -1,20 +1,25 @@ -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; - // bit of setup to mock HTTP request responses import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; + import { SupportedPlugin } from '../types/pluginBridges'; export const NON_EXISTING_PLUGIN = '__does_not_exist__'; const server = setupServer( - rest.get(`/api/plugins/${NON_EXISTING_PLUGIN}/settings`, async (_req, res, ctx) => res(ctx.status(404))), - rest.get(`/api/plugins/${SupportedPlugin.Incident}/settings`, async (_req, res, ctx) => { - return res( - ctx.json({ - enabled: true, - }) - ); + http.get(`/api/plugins/${NON_EXISTING_PLUGIN}/settings`, async () => + HttpResponse.json( + {}, + { + status: 404, + } + ) + ), + http.get(`/api/plugins/${SupportedPlugin.Incident}/settings`, async () => { + return HttpResponse.json({ + enabled: true, + }); }) ); diff --git a/public/app/features/alerting/unified/components/contact-points/__mocks__/grafanaManagedServer.ts b/public/app/features/alerting/unified/components/contact-points/__mocks__/grafanaManagedServer.ts index a93b7b046c0..54666de1aa5 100644 --- a/public/app/features/alerting/unified/components/contact-points/__mocks__/grafanaManagedServer.ts +++ b/public/app/features/alerting/unified/components/contact-points/__mocks__/grafanaManagedServer.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/node'; import { AlertmanagerChoice, AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types'; @@ -14,15 +15,15 @@ import receiversMock from './receivers.mock.json'; export default (server: SetupServer) => { server.use( // this endpoint is a grafana built-in alertmanager - rest.get('/api/alertmanager/grafana/config/api/v1/alerts', (_req, res, ctx) => - res(ctx.json(alertmanagerMock)) + http.get('/api/alertmanager/grafana/config/api/v1/alerts', () => + HttpResponse.json(alertmanagerMock) ), // this endpoint is only available for the built-in alertmanager - rest.get('/api/alertmanager/grafana/config/api/v1/receivers', (_req, res, ctx) => - res(ctx.json(receiversMock)) + http.get('/api/alertmanager/grafana/config/api/v1/receivers', () => + HttpResponse.json(receiversMock) ), // this endpoint will respond if the OnCall plugin is installed - rest.get('/api/plugins/grafana-oncall-app/settings', (_req, res, ctx) => res(ctx.status(404))) + http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 })) ); // this endpoint is for rendering the "additional AMs to configure" warning @@ -41,12 +42,18 @@ export const setupTestEndpointMock = (server: SetupServer) => { const mock = jest.fn(); server.use( - rest.post('/api/alertmanager/grafana/config/api/v1/receivers/test', async (req, res, ctx) => { - const requestBody = await req.json(); - mock(requestBody); + http.post( + '/api/alertmanager/grafana/config/api/v1/receivers/test', + async ({ request }) => { + const requestBody = await request.json(); + mock(requestBody); - return res.once(ctx.status(200)); - }) + return HttpResponse.json({}); + }, + { + once: true, + } + ) ); return mock; @@ -56,12 +63,18 @@ export const setupSaveEndpointMock = (server: SetupServer) => { const mock = jest.fn(); server.use( - rest.post('/api/alertmanager/grafana/config/api/v1/alerts', async (req, res, ctx) => { - const requestBody = await req.json(); - mock(requestBody); + http.post( + '/api/alertmanager/grafana/config/api/v1/alerts', + async ({ request }) => { + const requestBody = await request.json(); + mock(requestBody); - return res.once(ctx.status(200)); - }) + return HttpResponse.json({}); + }, + { + once: true, + } + ) ); return mock; diff --git a/public/app/features/alerting/unified/components/contact-points/__mocks__/mimirFlavoredServer.ts b/public/app/features/alerting/unified/components/contact-points/__mocks__/mimirFlavoredServer.ts index 88ef97018e9..adbed73cb48 100644 --- a/public/app/features/alerting/unified/components/contact-points/__mocks__/mimirFlavoredServer.ts +++ b/public/app/features/alerting/unified/components/contact-points/__mocks__/mimirFlavoredServer.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/lib/node'; import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types'; @@ -10,14 +11,20 @@ export const MIMIR_DATASOURCE_UID = 'mimir'; export default (server: SetupServer) => { server.use( - rest.get(`/api/alertmanager/${MIMIR_DATASOURCE_UID}/config/api/v1/alerts`, (_req, res, ctx) => - res(ctx.json(mimirAlertmanagerMock)) + http.get(`/api/alertmanager/${MIMIR_DATASOURCE_UID}/config/api/v1/alerts`, () => + HttpResponse.json(mimirAlertmanagerMock) ), - rest.get(`/api/datasources/proxy/uid/${MIMIR_DATASOURCE_UID}/api/v1/status/buildinfo`, (_req, res, ctx) => - res(ctx.status(404)) + http.get(`/api/datasources/proxy/uid/${MIMIR_DATASOURCE_UID}/api/v1/status/buildinfo`, () => + HttpResponse.json( + { + template_files: {}, + alertmanager_config: {}, + }, + { status: 404 } + ) ), // this endpoint will respond if the OnCall plugin is installed - rest.get('/api/plugins/grafana-oncall-app/settings', (_req, res, ctx) => res(ctx.status(404))) + http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 })) ); return server; diff --git a/public/app/features/alerting/unified/components/contact-points/__mocks__/vanillaAlertmanagerServer.ts b/public/app/features/alerting/unified/components/contact-points/__mocks__/vanillaAlertmanagerServer.ts index b834a5a515f..6c4943e28a2 100644 --- a/public/app/features/alerting/unified/components/contact-points/__mocks__/vanillaAlertmanagerServer.ts +++ b/public/app/features/alerting/unified/components/contact-points/__mocks__/vanillaAlertmanagerServer.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/lib/node'; import { AlertmanagerStatus } from 'app/plugins/datasource/alertmanager/types'; @@ -10,11 +11,11 @@ export const VANILLA_ALERTMANAGER_DATASOURCE_UID = 'alertmanager'; export default (server: SetupServer) => { server.use( - rest.get(`/api/alertmanager/${VANILLA_ALERTMANAGER_DATASOURCE_UID}/api/v2/status`, (_req, res, ctx) => - res(ctx.json(vanillaAlertManagerConfig)) + http.get(`/api/alertmanager/${VANILLA_ALERTMANAGER_DATASOURCE_UID}/api/v2/status`, () => + HttpResponse.json(vanillaAlertManagerConfig) ), // this endpoint will respond if the OnCall plugin is installed - rest.get('/api/plugins/grafana-oncall-app/settings', (_req, res, ctx) => res(ctx.status(404))) + http.get('/api/plugins/grafana-oncall-app/settings', () => HttpResponse.json({}, { status: 404 })) ); return server; diff --git a/public/app/features/alerting/unified/components/contact-points/utils.test.ts b/public/app/features/alerting/unified/components/contact-points/utils.test.ts new file mode 100644 index 00000000000..4e340e33577 --- /dev/null +++ b/public/app/features/alerting/unified/components/contact-points/utils.test.ts @@ -0,0 +1,157 @@ +import { GrafanaManagedContactPoint } from 'app/plugins/datasource/alertmanager/types'; + +import { ReceiverTypes } from '../receivers/grafanaAppReceivers/onCall/onCall'; + +import { RECEIVER_META_KEY, RECEIVER_PLUGIN_META_KEY } from './useContactPoints'; +import { + ReceiverConfigWithMetadata, + getReceiverDescription, + isAutoGeneratedPolicy, + isProvisioned, + summarizeEmailAddresses, +} from './utils'; + +describe('isProvisioned', () => { + it('should return true when at least one receiver is provisioned', () => { + const contactPoint: GrafanaManagedContactPoint = { + name: 'my-contact-point', + grafana_managed_receiver_configs: [ + { name: 'email', provenance: 'api', type: 'email', disableResolveMessage: false, settings: {} }, + ], + }; + + expect(isProvisioned(contactPoint)).toBe(true); + }); + + it('should return false when no receiver was provisioned', () => { + const contactPoint: GrafanaManagedContactPoint = { + name: 'my-contact-point', + grafana_managed_receiver_configs: [ + { name: 'email', provenance: undefined, type: 'email', disableResolveMessage: false, settings: {} }, + ], + }; + + expect(isProvisioned(contactPoint)).toBe(false); + }); +}); + +describe('isAutoGeneratedPolicy', () => { + it('should return false when not enabled', () => { + expect(isAutoGeneratedPolicy({})).toBe(false); + }); +}); + +describe('getReceiverDescription', () => { + it('should show multiple email addresses', () => { + const receiver: ReceiverConfigWithMetadata = { + name: 'email', + provenance: undefined, + type: 'email', + disableResolveMessage: false, + settings: { addresses: 'test1@test.com,test2@test.com,test3@test.com,test4@test.com' }, + [RECEIVER_META_KEY]: { + name: 'Email', + description: 'The email receiver', + }, + }; + + expect(getReceiverDescription(receiver)).toBe('test1@test.com, test2@test.com, test3@test.com, +1 more'); + }); + + it('should work for Slack', () => { + const output = '#channel'; + const receiver1: ReceiverConfigWithMetadata = { + name: 'slack', + provenance: undefined, + type: 'slack', + disableResolveMessage: false, + settings: { recipient: '#channel' }, + [RECEIVER_META_KEY]: { + name: 'Slack', + description: 'The Slack receiver', + }, + }; + + const receiver2: ReceiverConfigWithMetadata = { + name: 'slack', + provenance: undefined, + type: 'slack', + disableResolveMessage: false, + settings: { recipient: 'channel' }, + [RECEIVER_META_KEY]: { + name: 'Slack', + description: 'The Slack receiver', + }, + }; + + expect(getReceiverDescription(receiver1)).toBe(output); + expect(getReceiverDescription(receiver2)).toBe(output); + }); + + it('should work for OnCall', () => { + const output = 'The OnCall receiver'; + const input: ReceiverConfigWithMetadata = { + name: 'my oncall', + provenance: undefined, + type: ReceiverTypes.OnCall, + disableResolveMessage: false, + settings: {}, + [RECEIVER_PLUGIN_META_KEY]: { + description: output, + icon: '', + title: '', + }, + [RECEIVER_META_KEY]: { + name: '', + }, + }; + + expect(getReceiverDescription(input)).toBe(output); + }); + + it('should work for any type', () => { + const output = 'Some description of the receiver'; + const input: ReceiverConfigWithMetadata = { + name: 'some receiver', + provenance: undefined, + type: 'some', + disableResolveMessage: false, + settings: {}, + [RECEIVER_META_KEY]: { + name: 'Some Receiver', + description: output, + }, + }; + + expect(getReceiverDescription(input)).toBe(output); + }); + + it('should work for any type with no description', () => { + const input: ReceiverConfigWithMetadata = { + name: 'some receiver', + provenance: undefined, + type: 'some', + disableResolveMessage: false, + settings: {}, + [RECEIVER_META_KEY]: { + name: 'Some Receiver', + }, + }; + + expect(getReceiverDescription(input)).toBe(undefined); + }); +}); + +describe('summarizeEmailAddresses', () => { + it('should work with one email address', () => { + expect(summarizeEmailAddresses('test@test.com')).toBe('test@test.com'); + }); + + it('should work with multiple types of separators', () => { + const output = 'foo@foo.com, bar@bar.com'; + + expect(summarizeEmailAddresses('foo@foo.com, bar@bar.com')).toBe(output); + expect(summarizeEmailAddresses(' foo@foo.com; bar@bar.com')).toBe(output); + expect(summarizeEmailAddresses('foo@foo.com\n bar@bar.com ')).toBe(output); + }); +}); diff --git a/public/app/features/alerting/unified/components/contact-points/utils.ts b/public/app/features/alerting/unified/components/contact-points/utils.ts index 201351e1451..479bde2b494 100644 --- a/public/app/features/alerting/unified/components/contact-points/utils.ts +++ b/public/app/features/alerting/unified/components/contact-points/utils.ts @@ -1,4 +1,4 @@ -import { countBy, split, trim, upperFirst } from 'lodash'; +import { countBy, difference, take, trim, upperFirst } from 'lodash'; import { ReactNode } from 'react'; import { config } from '@grafana/runtime'; @@ -40,15 +40,21 @@ export function getReceiverDescription(receiver: ReceiverConfigWithMetadata): Re return hasEmailAddresses ? summarizeEmailAddresses(receiver.settings['addresses']) : undefined; } case 'slack': { - const channelName = receiver.settings['recipient']; - return channelName ? `#${channelName}` : undefined; + const recipient: string | undefined = receiver.settings['recipient']; + if (!recipient) { + return; + } + + // Slack channel name might have a "#" in the recipient already + const channelName = recipient.replace(/^#/, ''); + return `#${channelName}`; } case 'kafka': { - const topicName = receiver.settings['kafkaTopic']; + const topicName: string | undefined = receiver.settings['kafkaTopic']; return topicName; } case 'webhook': { - const url = receiver.settings['url']; + const url: string | undefined = receiver.settings['url']; return url; } case ReceiverTypes.OnCall: { @@ -61,20 +67,22 @@ export function getReceiverDescription(receiver: ReceiverConfigWithMetadata): Re // input: foo+1@bar.com, foo+2@bar.com, foo+3@bar.com, foo+4@bar.com // output: foo+1@bar.com, foo+2@bar.com, +2 more -function summarizeEmailAddresses(addresses: string): string { +export function summarizeEmailAddresses(addresses: string): string { const MAX_ADDRESSES_SHOWN = 3; const SUPPORTED_SEPARATORS = /,|;|\n+/g; + // split all email addresses const emails = addresses.trim().split(SUPPORTED_SEPARATORS).map(trim); - const notShown = emails.length - MAX_ADDRESSES_SHOWN; + // grab the first 3 and the rest + const summary = take(emails, MAX_ADDRESSES_SHOWN); + const rest = difference(emails, summary); - const truncatedAddresses = split(addresses, SUPPORTED_SEPARATORS, MAX_ADDRESSES_SHOWN); - if (notShown > 0) { - truncatedAddresses.push(`+${notShown} more`); + if (rest.length) { + summary.push(`+${rest.length} more`); } - return truncatedAddresses.join(', '); + return summary.join(', '); } // Grafana Managed contact points have receivers with additional diagnostics diff --git a/public/app/features/alerting/unified/components/rule-viewer/v2/__mocks__/server.ts b/public/app/features/alerting/unified/components/rule-viewer/v2/__mocks__/server.ts index a9ec31748fe..83584bb4155 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/v2/__mocks__/server.ts +++ b/public/app/features/alerting/unified/components/rule-viewer/v2/__mocks__/server.ts @@ -1,7 +1,7 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; -import 'whatwg-fetch'; import { AlertmanagersChoiceResponse } from 'app/features/alerting/unified/api/alertmanagerApi'; import { mockAlertmanagerChoiceResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi'; import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types'; @@ -33,16 +33,15 @@ export function createMockGrafanaServer() { // a user must alsso have permissions for the folder (namespace) in which the alert rule is stored function mockFolderAccess(server: SetupServer, accessControl: Partial>) { server.use( - rest.get('/api/folders/:uid', (req, res, ctx) => { - const uid = req.params.uid; + http.get('/api/folders/:uid', ({ request }) => { + const url = new URL(request.url); + const uid = url.searchParams.get('uid'); - return res( - ctx.json({ - title: 'My Folder', - uid, - accessControl, - }) - ); + return HttpResponse.json({ + title: 'My Folder', + uid, + accessControl, + }); }) ); @@ -51,8 +50,8 @@ function mockFolderAccess(server: SetupServer, accessControl: Partial { - return res(ctx.status(200)); + http.get('/api/plugins/grafana-incident-app/settings', () => { + return HttpResponse.json({}); }) ); } diff --git a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx index 9ee4496bd17..59e89009881 100644 --- a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx @@ -1,4 +1,6 @@ +import 'whatwg-fetch'; import { render, screen, waitFor } from '@testing-library/react'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import React from 'react'; import { Provider } from 'react-redux'; @@ -18,6 +20,7 @@ import { AlertmanagersChoiceResponse } from '../../api/alertmanagerApi'; import { useIsRuleEditable } from '../../hooks/useIsRuleEditable'; import { getCloudRule, getGrafanaRule } from '../../mocks'; import { mockAlertmanagerChoiceResponse } from '../../mocks/alertmanagerApi'; +import { SupportedPlugin } from '../../types/pluginBridges'; import { RuleDetails } from './RuleDetails'; @@ -42,7 +45,13 @@ const ui = { }, }; -const server = setupServer(); +const server = setupServer( + http.get(`/api/plugins/${SupportedPlugin.Incident}/settings`, async () => { + return HttpResponse.json({ + enabled: false, + }); + }) +); const alertmanagerChoiceMockedResponse: AlertmanagersChoiceResponse = { alertmanagersChoice: AlertmanagerChoice.Internal, @@ -74,6 +83,7 @@ beforeEach(() => { ], }); server.resetHandlers(); + mockAlertmanagerChoiceResponse(server, alertmanagerChoiceMockedResponse); }); describe('RuleDetails RBAC', () => { @@ -107,7 +117,6 @@ describe('RuleDetails RBAC', () => { it('Should not render Silence button for users wihout the instance create permission', async () => { // Arrange jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(false); - mockAlertmanagerChoiceResponse(server, alertmanagerChoiceMockedResponse); // Act renderRuleDetails(grafanaRule); @@ -118,8 +127,6 @@ describe('RuleDetails RBAC', () => { }); it('Should render Silence button for users with the instance create permissions', async () => { - mockAlertmanagerChoiceResponse(server, alertmanagerChoiceMockedResponse); - // Arrange jest .spyOn(contextSrv, 'hasPermission') diff --git a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx index b224dd8db30..3093caf579c 100644 --- a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx @@ -108,10 +108,12 @@ describe('Rules group tests', () => { groups: [group], }; - it('Should hide delete and edit group buttons', () => { + it('Should hide delete and edit group buttons', async () => { // Act mockUseHasRuler(true, true); + mockFolderApi(server).folder('cpu-usage', mockFolder({ uid: 'cpu-usage', canSave: false })); renderRulesGroup(namespace, group); + expect(await screen.findByTestId('rule-group')).toBeInTheDocument(); // Assert expect(ui.deleteGroupButton.query()).not.toBeInTheDocument(); diff --git a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx index 24380f45f3f..e9ba271cdec 100644 --- a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx +++ b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx @@ -1,9 +1,9 @@ +import 'whatwg-fetch'; import { render, waitFor } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import React from 'react'; import { byRole, byText } from 'testing-library-selector'; -import 'whatwg-fetch'; import { DataFrameJSON } from '@grafana/data'; import { setBackendSrv } from '@grafana/runtime'; @@ -20,53 +20,51 @@ beforeAll(() => { server.listen({ onUnhandledRequest: 'error' }); server.use( - rest.get('/api/v1/rules/history', (req, res, ctx) => - res( - ctx.json({ - data: { - values: [ - [1681739580000, 1681739580000, 1681739580000], - [ - { - previous: 'Normal', - current: 'Pending', - values: { - B: 0.010344684900897919, - C: 1, - }, - labels: { - handler: '/api/prometheus/grafana/api/v1/rules', - }, + http.get('/api/v1/rules/history', () => + HttpResponse.json({ + data: { + values: [ + [1681739580000, 1681739580000, 1681739580000], + [ + { + previous: 'Normal', + current: 'Pending', + values: { + B: 0.010344684900897919, + C: 1, }, - { - previous: 'Normal', - current: 'Pending', - values: { - B: 0.010344684900897919, - C: 1, - }, - dashboardUID: '', - panelID: 0, - labels: { - handler: '/api/live/ws', - }, + labels: { + handler: '/api/prometheus/grafana/api/v1/rules', }, - { - previous: 'Normal', - current: 'Pending', - values: { - B: 0.010344684900897919, - C: 1, - }, - labels: { - handler: '/api/folders/:uid/', - }, + }, + { + previous: 'Normal', + current: 'Pending', + values: { + B: 0.010344684900897919, + C: 1, }, - ], + dashboardUID: '', + panelID: 0, + labels: { + handler: '/api/live/ws', + }, + }, + { + previous: 'Normal', + current: 'Pending', + values: { + B: 0.010344684900897919, + C: 1, + }, + labels: { + handler: '/api/folders/:uid/', + }, + }, ], - }, - }) - ) + ], + }, + }) ) ); }); @@ -100,8 +98,8 @@ describe('LokiStateHistory', () => { it('should render no entries message when no records are returned', async () => { server.use( - rest.get('/api/v1/rules/history', (req, res, ctx) => - res(ctx.json({ data: { values: [] }, schema: { fields: [] } })) + http.get('/api/v1/rules/history', () => + HttpResponse.json({ data: { values: [] }, schema: { fields: [] } }) ) ); diff --git a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx index 6feda94a91c..1e15071190b 100644 --- a/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx +++ b/public/app/features/alerting/unified/hooks/useExternalAMSelector.test.tsx @@ -1,10 +1,9 @@ +import 'whatwg-fetch'; import { renderHook, waitFor } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; import { TestProvider } from 'test/helpers/TestProvider'; -import 'whatwg-fetch'; - import { DataSourceSettings } from '@grafana/data'; import { setBackendSrv } from '@grafana/runtime'; import { backendSrv } from 'app/core/services/backend_srv'; @@ -215,8 +214,8 @@ function setupAlertmanagerDataSource( }; server.use( - rest.get('/api/datasources', (_req, res, ctx) => { - return res(ctx.json([dsSettings])); + http.get('/api/datasources', () => { + return HttpResponse.json([dsSettings]); }) ); } diff --git a/public/app/features/alerting/unified/mockApi.ts b/public/app/features/alerting/unified/mockApi.ts index d603cbe42be..cd85c322815 100644 --- a/public/app/features/alerting/unified/mockApi.ts +++ b/public/app/features/alerting/unified/mockApi.ts @@ -1,7 +1,7 @@ -import { uniqueId } from 'lodash'; -import { rest } from 'msw'; -import { setupServer, SetupServer } from 'msw/node'; import 'whatwg-fetch'; +import { uniqueId } from 'lodash'; +import { http, HttpResponse } from 'msw'; +import { setupServer, SetupServer } from 'msw/node'; import { DataSourceInstanceSettings, PluginMeta } from '@grafana/data'; import { setBackendSrv } from '@grafana/runtime'; @@ -190,85 +190,74 @@ export function mockApi(server: SetupServer) { configure(builder); server.use( - rest.get(`api/alertmanager/${amName}/config/api/v1/alerts`, (req, res, ctx) => - res( - ctx.status(200), - ctx.json({ - alertmanager_config: builder.build(), - template_files: {}, - }) - ) + http.get(`api/alertmanager/${amName}/config/api/v1/alerts`, () => + HttpResponse.json({ + alertmanager_config: builder.build(), + template_files: {}, + }) ) ); }, eval: (response: AlertingQueryResponse) => { server.use( - rest.post('/api/v1/eval', (_, res, ctx) => { - return res(ctx.status(200), ctx.json(response)); + http.post('/api/v1/eval', () => { + return HttpResponse.json(response); }) ); }, grafanaNotifiers: (response: NotifierDTO[]) => { - server.use( - rest.get(`api/alert-notifiers`, (req, res, ctx) => res(ctx.status(200), ctx.json(response))) - ); + server.use(http.get(`api/alert-notifiers`, () => HttpResponse.json(response))); }, plugins: { getPluginSettings: (response: PluginMeta) => { - server.use( - rest.get(`api/plugins/${response.id}/settings`, (req, res, ctx) => - res(ctx.status(200), ctx.json(response)) - ) - ); + server.use(http.get(`api/plugins/${response.id}/settings`, () => HttpResponse.json(response))); }, }, oncall: { getOnCallIntegrations: (response: OnCallIntegrationDTO[]) => { server.use( - rest.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels`, (_, res, ctx) => - res(ctx.status(200), ctx.json(response)) + http.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels`, () => + HttpResponse.json(response) ) ); }, features: (response: string[]) => { server.use( - rest.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/features`, (_, res, ctx) => - res(ctx.status(200), ctx.json(response)) - ) + http.get(`api/plugin-proxy/grafana-oncall-app/api/internal/v1/features`, () => HttpResponse.json(response)) ); }, validateIntegrationName: (invalidNames: string[]) => { server.use( - rest.get( + http.get( `api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels/validate_name`, - (req, res, ctx) => { - const isValid = !invalidNames.includes(req.url.searchParams.get('verbal_name') ?? ''); - return res(ctx.status(isValid ? 200 : 409), ctx.json(isValid)); + ({ request }) => { + const url = new URL(request.url); + const isValid = !invalidNames.includes(url.searchParams.get('verbal_name') ?? ''); + return HttpResponse.json(isValid, { + status: isValid ? 200 : 409, + }); } ) ); }, createIntegraion: () => { server.use( - rest.post( + http.post<{}, CreateIntegrationDTO>( `api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels`, - async (req, res, ctx) => { - const body = await req.json(); + async ({ request }) => { + const body = await request.json(); const integrationId = uniqueId('oncall-integration-'); - return res( - ctx.status(200), - ctx.json({ - id: integrationId, - integration: body.integration, - integration_url: `https://oncall-endpoint.example.com/${integrationId}`, - verbal_name: body.verbal_name, - connected_escalations_chains_count: 0, - }) - ); + return HttpResponse.json({ + id: integrationId, + integration: body.integration, + integration_url: `https://oncall-endpoint.example.com/${integrationId}`, + verbal_name: body.verbal_name, + connected_escalations_chains_count: 0, + }); } ) ); @@ -281,21 +270,15 @@ export function mockAlertRuleApi(server: SetupServer) { return { prometheusRuleNamespaces: (dsName: string, response: PromRulesResponse) => { server.use( - rest.get(`api/prometheus/${dsName}/api/v1/rules`, (req, res, ctx) => - res(ctx.status(200), ctx.json(response)) - ) + http.get(`api/prometheus/${dsName}/api/v1/rules`, () => HttpResponse.json(response)) ); }, rulerRules: (dsName: string, response: RulerRulesConfigDTO) => { - server.use( - rest.get(`/api/ruler/${dsName}/api/v1/rules`, (req, res, ctx) => res(ctx.status(200), ctx.json(response))) - ); + server.use(http.get(`/api/ruler/${dsName}/api/v1/rules`, () => HttpResponse.json(response))); }, rulerRuleGroup: (dsName: string, namespace: string, group: string, response: RulerRuleGroupDTO) => { server.use( - rest.get(`/api/ruler/${dsName}/api/v1/rules/${namespace}/${group}`, (req, res, ctx) => - res(ctx.status(200), ctx.json(response)) - ) + http.get(`/api/ruler/${dsName}/api/v1/rules/${namespace}/${group}`, () => HttpResponse.json(response)) ); }, }; @@ -312,9 +295,7 @@ export function mockFeatureDiscoveryApi(server: SetupServer) { * @param response Use `buildInfoResponse` to get a pre-defined response for Prometheus and Mimir */ discoverDsFeatures: (dsSettings: DataSourceInstanceSettings, response: PromBuildInfoResponse) => { - server.use( - rest.get(`${dsSettings.url}/api/v1/status/buildinfo`, (_, res, ctx) => res(ctx.status(200), ctx.json(response))) - ); + server.use(http.get(`${dsSettings.url}/api/v1/status/buildinfo`, () => HttpResponse.json(response))); }, }; } @@ -323,16 +304,20 @@ export function mockProvisioningApi(server: SetupServer) { return { exportRuleGroup: (folderUid: string, groupName: string, response: Record) => { server.use( - rest.get(`/api/v1/provisioning/folder/${folderUid}/rule-groups/${groupName}/export`, (req, res, ctx) => - res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])) - ) + http.get(`/api/v1/provisioning/folder/${folderUid}/rule-groups/${groupName}/export`, ({ request }) => { + const url = new URL(request.url); + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); + }) ); }, exportReceiver: (response: Record) => { server.use( - rest.get(`/api/v1/provisioning/contact-points/export/`, (req, res, ctx) => - res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])) - ) + http.get(`/api/v1/provisioning/contact-points/export/`, ({ request }) => { + const url = new URL(request.url); + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); + }) ); }, }; @@ -344,43 +329,51 @@ export function mockExportApi(server: SetupServer) { // exportRule requires ruleUid parameter and doesn't allow folderUid and group parameters exportRule: (ruleUid: string, response: Record) => { server.use( - rest.get('/api/ruler/grafana/api/v1/export/rules', (req, res, ctx) => { - if (req.url.searchParams.get('ruleUid') === ruleUid) { - return res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])); + http.get('/api/ruler/grafana/api/v1/export/rules', ({ request }) => { + const url = new URL(request.url); + if (url.searchParams.get('ruleUid') === ruleUid) { + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); } - return res(ctx.status(500)); + return HttpResponse.text('', { status: 500 }); }) ); }, // exportRulesGroup requires folderUid and group parameters and doesn't allow ruleUid parameter exportRulesGroup: (folderUid: string, group: string, response: Record) => { server.use( - rest.get('/api/ruler/grafana/api/v1/export/rules', (req, res, ctx) => { - if (req.url.searchParams.get('folderUid') === folderUid && req.url.searchParams.get('group') === group) { - return res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])); + http.get('/api/ruler/grafana/api/v1/export/rules', ({ request }) => { + const url = new URL(request.url); + if (url.searchParams.get('folderUid') === folderUid && url.searchParams.get('group') === group) { + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); } - return res(ctx.status(500)); + return HttpResponse.text('', { status: 500 }); }) ); }, // exportRulesFolder requires folderUid parameter exportRulesFolder: (folderUid: string, response: Record) => { server.use( - rest.get('/api/ruler/grafana/api/v1/export/rules', (req, res, ctx) => { - if (req.url.searchParams.get('folderUid') === folderUid) { - return res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])); + http.get('/api/ruler/grafana/api/v1/export/rules', ({ request }) => { + const url = new URL(request.url); + if (url.searchParams.get('folderUid') === folderUid) { + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); } - return res(ctx.status(500)); + return HttpResponse.text('', { status: 500 }); }) ); }, modifiedExport: (namespaceUID: string, response: Record) => { server.use( - rest.post(`/api/ruler/grafana/api/v1/rules/${namespaceUID}/export`, (req, res, ctx) => { - return res(ctx.status(200), ctx.text(response[req.url.searchParams.get('format') ?? 'yaml'])); + http.post(`/api/ruler/grafana/api/v1/rules/${namespaceUID}/export`, ({ request }) => { + const url = new URL(request.url); + const format = url.searchParams.get('format') ?? 'yaml'; + return HttpResponse.text(response[format]); }) ); }, @@ -390,7 +383,7 @@ export function mockExportApi(server: SetupServer) { export function mockFolderApi(server: SetupServer) { return { folder: (folderUid: string, response: FolderDTO) => { - server.use(rest.get(`/api/folders/${folderUid}`, (_, res, ctx) => res(ctx.status(200), ctx.json(response)))); + server.use(http.get(`/api/folders/${folderUid}`, () => HttpResponse.json(response))); }, }; } @@ -398,7 +391,7 @@ export function mockFolderApi(server: SetupServer) { export function mockSearchApi(server: SetupServer) { return { search: (results: DashboardSearchItem[]) => { - server.use(rest.get(`/api/search`, (_, res, ctx) => res(ctx.status(200), ctx.json(results)))); + server.use(http.get(`/api/search`, () => HttpResponse.json(results))); }, }; } @@ -406,14 +399,10 @@ export function mockSearchApi(server: SetupServer) { export function mockDashboardApi(server: SetupServer) { return { search: (results: DashboardSearchItem[]) => { - server.use(rest.get(`/api/search`, (_, res, ctx) => res(ctx.status(200), ctx.json(results)))); + server.use(http.get(`/api/search`, () => HttpResponse.json(results))); }, dashboard: (response: DashboardDTO) => { - server.use( - rest.get(`/api/dashboards/uid/${response.dashboard.uid}`, (_, res, ctx) => - res(ctx.status(200), ctx.json(response)) - ) - ); + server.use(http.get(`/api/dashboards/uid/${response.dashboard.uid}`, () => HttpResponse.json(response))); }, }; } diff --git a/public/app/features/alerting/unified/mocks/alertRuleApi.ts b/public/app/features/alerting/unified/mocks/alertRuleApi.ts index 7eb598b37fa..d748fb8973a 100644 --- a/public/app/features/alerting/unified/mocks/alertRuleApi.ts +++ b/public/app/features/alerting/unified/mocks/alertRuleApi.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/node'; import { PromRulesResponse } from 'app/types/unified-alerting-dto'; @@ -6,9 +7,9 @@ import { PromRulesResponse } from 'app/types/unified-alerting-dto'; import { PreviewResponse, PREVIEW_URL, PROM_RULES_URL } from '../api/alertRuleApi'; export function mockPreviewApiResponse(server: SetupServer, result: PreviewResponse) { - server.use(rest.post(PREVIEW_URL, (req, res, ctx) => res(ctx.json(result)))); + server.use(http.post(PREVIEW_URL, () => HttpResponse.json(result))); } export function mockPromRulesApiResponse(server: SetupServer, result: PromRulesResponse) { - server.use(rest.get(PROM_RULES_URL, (req, res, ctx) => res(ctx.json(result)))); + server.use(http.get(PROM_RULES_URL, () => HttpResponse.json(result))); } diff --git a/public/app/features/alerting/unified/mocks/alertmanagerApi.ts b/public/app/features/alerting/unified/mocks/alertmanagerApi.ts index 492e01e74a2..1b7e98806dc 100644 --- a/public/app/features/alerting/unified/mocks/alertmanagerApi.ts +++ b/public/app/features/alerting/unified/mocks/alertmanagerApi.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/node'; import { @@ -14,7 +15,7 @@ export const defaultAlertmanagerChoiceResponse: AlertmanagersChoiceResponse = { numExternalAlertmanagers: 0, }; export function mockAlertmanagerChoiceResponse(server: SetupServer, response: AlertmanagersChoiceResponse) { - server.use(rest.get('/api/v1/ngalert', (req, res, ctx) => res(ctx.status(200), ctx.json(response)))); + server.use(http.get('/api/v1/ngalert', () => HttpResponse.json(response))); } export const emptyExternalAlertmanagersResponse: ExternalAlertmanagersResponse = { @@ -24,7 +25,7 @@ export const emptyExternalAlertmanagersResponse: ExternalAlertmanagersResponse = }, }; export function mockAlertmanagersResponse(server: SetupServer, response: ExternalAlertmanagersResponse) { - server.use(rest.get('/api/v1/ngalert/alertmanagers', (req, res, ctx) => res(ctx.status(200), ctx.json(response)))); + server.use(http.get('/api/v1/ngalert/alertmanagers', () => HttpResponse.json(response))); } export function mockAlertmanagerConfigResponse( @@ -33,8 +34,8 @@ export function mockAlertmanagerConfigResponse( response: AlertManagerCortexConfig ) { server.use( - rest.get(`/api/alertmanager/${getDatasourceAPIUid(alertManagerSourceName)}/config/api/v1/alerts`, (req, res, ctx) => - res(ctx.status(200), ctx.json(response)) + http.get(`/api/alertmanager/${getDatasourceAPIUid(alertManagerSourceName)}/config/api/v1/alerts`, () => + HttpResponse.json(response) ) ); } diff --git a/public/app/features/alerting/unified/mocks/plugins.ts b/public/app/features/alerting/unified/mocks/plugins.ts index eb8a2b5eab7..df657222de9 100644 --- a/public/app/features/alerting/unified/mocks/plugins.ts +++ b/public/app/features/alerting/unified/mocks/plugins.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/lib/node'; import { PluginMeta } from '@grafana/data'; @@ -7,8 +8,11 @@ import { SupportedPlugin } from '../types/pluginBridges'; export function mockPluginSettings(server: SetupServer, plugin: SupportedPlugin, response?: PluginMeta) { server.use( - rest.get(`/api/plugins/${plugin}/settings`, (_req, res, ctx) => { - return response ? res(ctx.status(200), ctx.json(response)) : res(ctx.status(404)); + http.get(`/api/plugins/${plugin}/settings`, () => { + if (response) { + return HttpResponse.json(response); + } + return HttpResponse.json({}, { status: 404 }); }) ); } diff --git a/public/app/features/alerting/unified/mocks/rulerApi.ts b/public/app/features/alerting/unified/mocks/rulerApi.ts index 71339a4cf72..d689d02382f 100644 --- a/public/app/features/alerting/unified/mocks/rulerApi.ts +++ b/public/app/features/alerting/unified/mocks/rulerApi.ts @@ -1,14 +1,11 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/node'; import { RulerRuleGroupDTO, RulerRulesConfigDTO } from '../../../../types/unified-alerting-dto'; export function mockRulerRulesApiResponse(server: SetupServer, rulesSourceName: string, response: RulerRulesConfigDTO) { - server.use( - rest.get(`/api/ruler/${rulesSourceName}/api/v1/rules`, (req, res, ctx) => - res(ctx.json(response)) - ) - ); + server.use(http.get(`/api/ruler/${rulesSourceName}/api/v1/rules`, () => HttpResponse.json(response))); } export function mockRulerRulesGroupApiResponse( @@ -19,8 +16,6 @@ export function mockRulerRulesGroupApiResponse( response: RulerRuleGroupDTO ) { server.use( - rest.get(`/api/ruler/${rulesSourceName}/api/v1/rules/${namespace}/${group}`, (req, res, ctx) => - res(ctx.json(response)) - ) + http.get(`/api/ruler/${rulesSourceName}/api/v1/rules/${namespace}/${group}`, () => HttpResponse.json(response)) ); } diff --git a/public/app/features/alerting/unified/mocks/templatesApi.ts b/public/app/features/alerting/unified/mocks/templatesApi.ts index cb6d18d4cf3..d0e591fb3c5 100644 --- a/public/app/features/alerting/unified/mocks/templatesApi.ts +++ b/public/app/features/alerting/unified/mocks/templatesApi.ts @@ -1,12 +1,13 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { SetupServer } from 'msw/node'; import { previewTemplateUrl, TemplatePreviewResponse } from '../api/templateApi'; export function mockPreviewTemplateResponse(server: SetupServer, response: TemplatePreviewResponse) { - server.use(rest.post(previewTemplateUrl, (req, res, ctx) => res(ctx.status(200), ctx.json(response)))); + server.use(http.post(previewTemplateUrl, () => HttpResponse.json(response))); } export function mockPreviewTemplateResponseRejected(server: SetupServer) { - server.use(rest.post(previewTemplateUrl, (req, res, ctx) => res(ctx.status(500), ctx.json('error')))); + server.use(http.post(previewTemplateUrl, () => HttpResponse.json('error', { status: 500 }))); } diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx index bb9f53b1afb..ab005ac3d48 100644 --- a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx +++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx @@ -1,7 +1,7 @@ -import 'whatwg-fetch'; // fetch polyfill +import 'whatwg-fetch'; import { render as rtlRender, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { rest } from 'msw'; +import { HttpResponse, http } from 'msw'; import { setupServer, SetupServer } from 'msw/node'; import React, { ComponentProps } from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; @@ -120,25 +120,19 @@ describe('browse-dashboards BrowseDashboardsPage', () => { beforeAll(() => { server = setupServer( - rest.get('/api/folders/:uid', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - title: folderA.item.title, - uid: folderA.item.uid, - }) - ); + http.get('/api/folders/:uid', () => { + return HttpResponse.json({ + title: folderA.item.title, + uid: folderA.item.uid, + }); }), - rest.get('/api/search', (_, res, ctx) => { - return res(ctx.status(200), ctx.json({})); + http.get('/api/search', () => { + return HttpResponse.json({}); }), - rest.get('/api/search/sorting', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - sortOptions: [], - }) - ); + http.get('/api/search/sorting', () => { + return HttpResponse.json({ + sortOptions: [], + }); }) ); server.listen(); diff --git a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx index e7f01c2a7e1..9c101f9bb54 100644 --- a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx +++ b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx @@ -1,6 +1,6 @@ -import 'whatwg-fetch'; // fetch polyfill +import 'whatwg-fetch'; import { render as rtlRender, screen } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; import React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; @@ -47,20 +47,17 @@ describe('browse-dashboards BrowseFolderAlertingPage', () => { beforeAll(() => { server = setupServer( - rest.get('/api/folders/:uid', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - title: mockFolderName, - uid: mockFolderUid, - }) - ); + http.get('/api/folders/:uid', () => { + return HttpResponse.json({ + title: mockFolderName, + uid: mockFolderUid, + }); }), - rest.get('api/ruler/grafana/api/v1/rules', (_, res, ctx) => { - return res(ctx.status(200), ctx.json(mockRulerRulesResponse)); + http.get('api/ruler/grafana/api/v1/rules', () => { + return HttpResponse.json(mockRulerRulesResponse); }), - rest.get('api/prometheus/grafana/api/v1/rules', (_, res, ctx) => { - return res(ctx.status(200), ctx.json(mockPrometheusRulesResponse)); + http.get('api/prometheus/grafana/api/v1/rules', () => { + return HttpResponse.json(mockPrometheusRulesResponse); }) ); server.listen(); diff --git a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx index b188fd20a93..1c6632d580b 100644 --- a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx +++ b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx @@ -1,6 +1,6 @@ -import 'whatwg-fetch'; // fetch polyfill +import 'whatwg-fetch'; import { render as rtlRender, screen } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { SetupServer, setupServer } from 'msw/node'; import React from 'react'; import { TestProvider } from 'test/helpers/TestProvider'; @@ -47,25 +47,19 @@ describe('browse-dashboards BrowseFolderLibraryPanelsPage', () => { beforeAll(() => { server = setupServer( - rest.get('/api/folders/:uid', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - title: mockFolderName, - uid: mockFolderUid, - }) - ); + http.get('/api/folders/:uid', () => { + return HttpResponse.json({ + title: mockFolderName, + uid: mockFolderUid, + }); }), - rest.get('/api/library-elements', (_, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - result: mockLibraryElementsResponse, - }) - ); + http.get('/api/library-elements', () => { + return HttpResponse.json({ + result: mockLibraryElementsResponse, + }); }), - rest.get('/api/search/sorting', (_, res, ctx) => { - return res(ctx.status(200), ctx.json({})); + http.get('/api/search/sorting', () => { + return HttpResponse.json({}); }) ); server.listen(); diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx index 9d44e50e689..66a5c9816f5 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx @@ -144,7 +144,7 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) { const currentTab = tabs.find((t) => t.tabId === tab); return ( - <> +
{tabs.map((t, index) => { return ( @@ -161,12 +161,19 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) { {currentTab && } - +
); } function getStyles(theme: GrafanaTheme2) { return { + dataPane: css({ + display: 'flex', + flexDirection: 'column', + flexGrow: 1, + minHeight: 0, + height: '100%', + }), tabContent: css({ padding: theme.spacing(2), border: `1px solid ${theme.colors.border.weak}`, diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditor.test.ts b/public/app/features/dashboard-scene/panel-edit/PanelEditor.test.ts index 874d24c2257..d2f1261a4e6 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelEditor.test.ts +++ b/public/app/features/dashboard-scene/panel-edit/PanelEditor.test.ts @@ -1,10 +1,9 @@ import { PanelPlugin, PanelPluginMeta, PluginType } from '@grafana/data'; -import { SceneFlexItem, SceneGridItem, SceneGridLayout, SplitLayout, VizPanel } from '@grafana/scenes'; +import { SceneGridItem, SceneGridLayout, VizPanel } from '@grafana/scenes'; import { DashboardScene } from '../scene/DashboardScene'; import { activateFullSceneTree } from '../utils/test-utils'; -import { PanelDataPane } from './PanelDataPane/PanelDataPane'; import { buildPanelEditScene } from './PanelEditor'; let pluginToLoad: PanelPlugin | undefined; @@ -47,8 +46,7 @@ describe('PanelEditor', () => { const deactivate = activateFullSceneTree(scene); - const vizManager = editScene.state.panelRef.resolve(); - vizManager.state.panel.setState({ title: 'changed title' }); + editScene.state.vizManager.state.panel.setState({ title: 'changed title' }); deactivate(); @@ -72,7 +70,7 @@ describe('PanelEditor', () => { activateFullSceneTree(scene); - expect(((editScene.state.body as SplitLayout).state.primary as SplitLayout).state.secondary).toBeUndefined(); + expect(editScene.state.dataPane).toBeUndefined(); }); it('should exist if panel is supporting querying', () => { @@ -88,10 +86,7 @@ describe('PanelEditor', () => { }); activateFullSceneTree(scene); - const secondaryPane = ((editScene.state.body as SplitLayout).state.primary as SplitLayout).state.secondary; - - expect(secondaryPane).toBeInstanceOf(SceneFlexItem); - expect((secondaryPane as SceneFlexItem).state.body).toBeInstanceOf(PanelDataPane); + expect(editScene.state.dataPane).toBeDefined(); }); }); }); diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx index e7e22365769..e88c5c3f28f 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx @@ -2,17 +2,7 @@ import * as H from 'history'; import { NavIndex } from '@grafana/data'; import { config, locationService } from '@grafana/runtime'; -import { - SceneFlexItem, - SceneFlexLayout, - SceneGridItem, - SceneObject, - SceneObjectBase, - SceneObjectRef, - SceneObjectState, - SplitLayout, - VizPanel, -} from '@grafana/scenes'; +import { SceneGridItem, SceneObject, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes'; import { findVizPanelByKey, @@ -27,11 +17,12 @@ import { PanelOptionsPane } from './PanelOptionsPane'; import { VizPanelManager } from './VizPanelManager'; export interface PanelEditorState extends SceneObjectState { - body: SceneObject; controls?: SceneObject[]; isDirty?: boolean; panelId: number; - panelRef: SceneObjectRef; + optionsPane?: PanelOptionsPane; + dataPane?: PanelDataPane; + vizManager: VizPanelManager; } export class PanelEditor extends SceneObjectBase { @@ -42,14 +33,41 @@ export class PanelEditor extends SceneObjectBase { public constructor(state: PanelEditorState) { super(state); - this.addActivationHandler(() => { - return () => { - if (!this._discardChanges) { - this.commitChanges(); - } - }; - }); + this.addActivationHandler(this._activationHandler.bind(this)); } + + private _activationHandler() { + const panelManager = this.state.vizManager; + const panel = panelManager.state.panel; + + this._subs.add( + panelManager.subscribeToState((n, p) => { + if (n.panel.state.pluginId !== p.panel.state.pluginId) { + this._initDataPane(n.panel.state.pluginId); + } + }) + ); + + this._initDataPane(panel.state.pluginId); + + return () => { + if (!this._discardChanges) { + this.commitChanges(); + } + }; + } + + private _initDataPane(pluginId: string) { + const skipDataQuery = config.panels[pluginId].skipDataQuery; + + if (!skipDataQuery && !this.state.dataPane) { + this.setState({ dataPane: new PanelDataPane(this.state.vizManager) }); + } else if (this.state.dataPane) { + locationService.partial({ tab: null }, true); + this.setState({ dataPane: undefined }); + } + } + public getUrlKey() { return this.state.panelId.toString(); } @@ -76,10 +94,20 @@ export class PanelEditor extends SceneObjectBase { dashboard.onEnterEditMode(); } - const panelMngr = this.state.panelRef.resolve(); - if (sourcePanel!.parent instanceof SceneGridItem) { - sourcePanel!.parent.setState({ body: panelMngr.state.panel.clone() }); + sourcePanel!.parent.setState({ body: this.state.vizManager.state.panel.clone() }); + } + } + + public toggleOptionsPane(withOpenVizPicker?: boolean) { + if (this.state.optionsPane) { + this.setState({ optionsPane: undefined }); + } else { + this.setState({ + optionsPane: new PanelOptionsPane({ + isVizPickerOpen: withOpenVizPicker, + }), + }); } } } @@ -90,78 +118,7 @@ export function buildPanelEditScene(panel: VizPanel): PanelEditor { return new PanelEditor({ panelId: getPanelIdForVizPanel(panel), - panelRef: vizPanelMgr.getRef(), - body: new SplitLayout({ - direction: 'row', - initialSize: 0.75, - primary: new SplitLayout({ - direction: 'column', - $behaviors: [conditionalDataPaneBehavior], - primary: new SceneFlexLayout({ - direction: 'column', - minHeight: 200, - children: [vizPanelMgr], - }), - primaryPaneStyles: { - minHeight: 0, - overflow: 'hidden', - }, - secondaryPaneStyles: { - minHeight: 0, - }, - }), - secondary: new SceneFlexItem({ - body: new PanelOptionsPane(vizPanelMgr), - width: '100%', - }), - primaryPaneStyles: { - minWidth: '0', - }, - secondaryPaneStyles: { - minWidth: '0', - }, - }), + optionsPane: new PanelOptionsPane({}), + vizManager: vizPanelMgr, }); } - -// This function is used to conditionally add the data pane to the panel editor, -// depending on the type of a panel being edited. -function conditionalDataPaneBehavior(scene: SplitLayout) { - const dashboard = getDashboardSceneFor(scene); - - const editor = dashboard.state.editPanel; - - if (!editor) { - return; - } - - const panelManager = editor.state.panelRef.resolve(); - const panel = panelManager.state.panel; - - const getDataPane = () => - new SceneFlexItem({ - body: new PanelDataPane(panelManager), - }); - - if (!config.panels[panel.state.pluginId].skipDataQuery) { - scene.setState({ - secondary: getDataPane(), - }); - } - - const sub = panelManager.subscribeToState((n, p) => { - const hadDataSupport = !config.panels[p.panel.state.pluginId].skipDataQuery; - const willHaveDataSupport = !config.panels[n.panel.state.pluginId].skipDataQuery; - - if (hadDataSupport && !willHaveDataSupport) { - locationService.partial({ tab: null }, true); - scene.setState({ secondary: undefined }); - } else if (!hadDataSupport && willHaveDataSupport) { - scene.setState({ secondary: getDataPane() }); - } - }); - - return () => { - sub.unsubscribe(); - }; -} diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx index f3ab6279ef2..8316b8b2ac9 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx @@ -3,16 +3,17 @@ import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { SceneComponentProps } from '@grafana/scenes'; -import { useStyles2 } from '@grafana/ui'; +import { Splitter, useStyles2 } from '@grafana/ui'; import { NavToolbarActions } from '../scene/NavToolbarActions'; import { getDashboardSceneFor } from '../utils/utils'; import { PanelEditor } from './PanelEditor'; +import { VisualizationButton } from './PanelOptionsPane'; export function PanelEditorRenderer({ model }: SceneComponentProps) { const dashboard = getDashboardSceneFor(model); - const { body } = model.useState(); + const { optionsPane, vizManager, dataPane } = model.useState(); const { controls } = dashboard.useState(); const styles = useStyles2(getStyles); @@ -25,10 +26,34 @@ export function PanelEditorRenderer({ model }: SceneComponentProps) {controls.map((control) => ( ))} + {!optionsPane && ( + model.toggleOptionsPane(true)} + isOpen={false} + onTogglePane={() => model.toggleOptionsPane()} + /> + )} )}
- + + + + {dataPane && } + + {optionsPane && } +
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx index b73fd69f04b..a1da35bb3c4 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx @@ -11,8 +11,8 @@ import { getPanelFrameCategory2 } from 'app/features/dashboard/components/PanelE import { getVisualizationOptions2 } from 'app/features/dashboard/components/PanelEditor/getVisualizationOptions'; import { getAllPanelPluginMeta } from 'app/features/panel/state/util'; +import { PanelEditor } from './PanelEditor'; import { PanelVizTypePicker } from './PanelVizTypePicker'; -import { VizPanelManager } from './VizPanelManager'; export interface PanelOptionsPaneState extends SceneObjectState { isVizPickerOpen?: boolean; @@ -21,15 +21,16 @@ export interface PanelOptionsPaneState extends SceneObjectState { } export class PanelOptionsPane extends SceneObjectBase { - public panelManager: VizPanelManager; - - public constructor(panelMgr: VizPanelManager) { + public constructor(state: Partial) { super({ searchQuery: '', listMode: OptionFilter.All, + ...state, }); + } - this.panelManager = panelMgr; + public getVizManager() { + return sceneGraph.getAncestor(this, PanelEditor).state.vizManager; } onToggleVizPicker = () => { @@ -44,11 +45,14 @@ export class PanelOptionsPane extends SceneObjectBase { this.setState({ listMode }); }; - onCollapsePane = () => {}; + onCollapsePane = () => { + const editor = sceneGraph.getAncestor(this, PanelEditor); + editor.toggleOptionsPane(); + }; static Component = ({ model }: SceneComponentProps) => { const { isVizPickerOpen, searchQuery, listMode } = model.useState(); - const { panelManager } = model; + const panelManager = model.getVizManager(); const { panel } = panelManager.state; const dataObject = sceneGraph.getData(panel); const { data } = dataObject.useState(); diff --git a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx index c9eab250ced..1048d4a0d0e 100644 --- a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx @@ -506,11 +506,9 @@ describe('VizPanelManager', () => { describe('change transformations', () => { it('should update and reprocess transformations', () => { const { scene, panel } = setupTest('panel-3'); - scene.setState({ - editPanel: buildPanelEditScene(panel), - }); + scene.setState({ editPanel: buildPanelEditScene(panel) }); - const vizPanelManager = scene.state.editPanel!.state.panelRef.resolve(); + const vizPanelManager = scene.state.editPanel!.state.vizManager; vizPanelManager.activate(); vizPanelManager.state.panel.state.$data?.activate(); @@ -560,11 +558,9 @@ describe('VizPanelManager', () => { describe('dashboard queries', () => { it('should update queries', () => { const { scene, panel } = setupTest('panel-3'); - scene.setState({ - editPanel: buildPanelEditScene(panel), - }); + scene.setState({ editPanel: buildPanelEditScene(panel) }); - const vizPanelManager = scene.state.editPanel!.state.panelRef.resolve(); + const vizPanelManager = scene.state.editPanel!.state.vizManager; vizPanelManager.activate(); vizPanelManager.state.panel.state.$data?.activate(); @@ -578,6 +574,7 @@ describe('VizPanelManager', () => { panelId: panelWithTransformations.id, }, ]); + expect(vizPanelManager.panelData).toBeInstanceOf(SceneDataTransformer); expect(vizPanelManager.queryRunner.state.queries[0].panelId).toEqual(panelWithTransformations.id); diff --git a/public/app/features/dashboard-scene/saving/getSaveDashboardChange.test.ts b/public/app/features/dashboard-scene/saving/getSaveDashboardChange.test.ts index 3c4b5577ed4..553d2bc0683 100644 --- a/public/app/features/dashboard-scene/saving/getSaveDashboardChange.test.ts +++ b/public/app/features/dashboard-scene/saving/getSaveDashboardChange.test.ts @@ -71,8 +71,7 @@ describe('getSaveDashboardChange', () => { dashboard.onEnterEditMode(); dashboard.setState({ editPanel: editScene }); - const vizManager = editScene.state.panelRef.resolve(); - vizManager.state.panel.setState({ title: 'changed title' }); + editScene.state.vizManager.state.panel.setState({ title: 'changed title' }); const result = getSaveDashboardChange(dashboard, false, true); const panelSaveModel = result.changedSaveModel.panels![0]; diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts index 406a844abe5..5b922de6bc3 100644 --- a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts +++ b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts @@ -147,7 +147,7 @@ class ResolveInspectPanelByKey extends SceneObjectBase { }); const getNonExistentPublicDashboardResponse = () => - rest.get('/api/dashboards/uid/:dashboardUid/public-dashboards', (req, res, ctx) => { - return res( - ctx.status(404), - ctx.json({ + http.get('/api/dashboards/uid/:dashboardUid/public-dashboards', () => { + return HttpResponse.json( + { message: 'Public dashboard not found', messageId: 'publicdashboards.notFound', statusCode: 404, traceID: '', - }) + }, + { + status: 404, + } ); }); const getErrorPublicDashboardResponse = () => - rest.get('/api/dashboards/uid/:dashboardUid/public-dashboards', (req, res, ctx) => { - return res(ctx.status(500)); + http.get('/api/dashboards/uid/:dashboardUid/public-dashboards', () => { + return HttpResponse.json( + {}, + { + status: 500, + } + ); }); const alertTests = () => { @@ -277,14 +284,11 @@ describe('SharePublic - Already persisted', () => { }); it('when modal is opened, then time range switch is enabled and not checked when its not checked in the db', async () => { server.use( - rest.get('/api/dashboards/uid/:dashboardUid/public-dashboards', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ...pubdashResponse, - timeSelectionEnabled: false, - }) - ); + http.get('/api/dashboards/uid/:dashboardUid/public-dashboards', () => { + return HttpResponse.json({ + ...pubdashResponse, + timeSelectionEnabled: false, + }); }) ); @@ -303,17 +307,16 @@ describe('SharePublic - Already persisted', () => { }); it('when pubdash is disabled in the db, then link url is not copyable and switch is checked', async () => { server.use( - rest.get('/api/dashboards/uid/:dashboardUid/public-dashboards', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - isEnabled: false, - annotationsEnabled: false, - uid: 'a-uid', - dashboardUid: req.params.dashboardUid, - accessToken: 'an-access-token', - }) - ); + http.get('/api/dashboards/uid/:dashboardUid/public-dashboards', ({ request }) => { + const url = new URL(request.url); + const dashboardUid = url.searchParams.get('dashboardUid'); + return HttpResponse.json({ + isEnabled: false, + annotationsEnabled: false, + uid: 'a-uid', + dashboardUid, + accessToken: 'an-access-token', + }); }) ); @@ -339,15 +342,14 @@ describe('SharePublic - Report interactions', () => { jest.clearAllMocks(); server.use(getExistentPublicDashboardResponse()); server.use( - rest.patch('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', (req, res, ctx) => - res( - ctx.status(200), - ctx.json({ - ...pubdashResponse, - dashboardUid: req.params.dashboardUid, - }) - ) - ) + http.patch('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', ({ request }) => { + const url = new URL(request.url); + const dashboardUid = url.searchParams.get('dashboardUid'); + return HttpResponse.json({ + ...pubdashResponse, + dashboardUid, + }); + }) ); }); diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx index 3d2bc135502..382c499e3a5 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx @@ -1,5 +1,6 @@ +import 'whatwg-fetch'; import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import React from 'react'; import { Provider } from 'react-redux'; @@ -32,15 +33,14 @@ export const pubdashResponse: sharePublicDashboardUtils.PublicDashboard = { }; export const getExistentPublicDashboardResponse = (publicDashboard?: Partial) => - rest.get('/api/dashboards/uid/:dashboardUid/public-dashboards', (req, res, ctx) => { - return res( - ctx.status(200), - ctx.json({ - ...pubdashResponse, - ...publicDashboard, - dashboardUid: req.params.dashboardUid, - }) - ); + http.get('/api/dashboards/uid/:dashboardUid/public-dashboards', ({ request }) => { + const url = new URL(request.url); + const dashboardUid = url.searchParams.get('dashboardUid'); + return HttpResponse.json({ + ...pubdashResponse, + ...publicDashboard, + dashboardUid, + }); }); export const renderSharePublicDashboard = async ( diff --git a/public/app/features/explore/Logs/LogsTable.test.tsx b/public/app/features/explore/Logs/LogsTable.test.tsx index 7eb047add6f..b22a2277395 100644 --- a/public/app/features/explore/Logs/LogsTable.test.tsx +++ b/public/app/features/explore/Logs/LogsTable.test.tsx @@ -164,7 +164,7 @@ describe('LogsTable', () => { }); }); - it('should not render `tsNs`', async () => { + it('should not render `tsNs` column', async () => { setup(undefined, getMockLokiFrame()); await waitFor(() => { @@ -174,6 +174,28 @@ describe('LogsTable', () => { }); }); + it('should render numeric field aligned right', async () => { + setup( + { + columnsWithMeta: { + Time: { active: true, percentOfLinesWithLabel: 100, index: 0 }, + line: { active: true, percentOfLinesWithLabel: 100, index: 1 }, + tsNs: { active: true, percentOfLinesWithLabel: 100, index: 2 }, + }, + }, + getMockLokiFrame() + ); + + await waitFor(() => { + const columns = screen.queryAllByRole('columnheader', { name: 'tsNs' }); + expect(columns.length).toBe(1); + }); + + const cells = screen.queryAllByRole('cell'); + + expect(cells[cells.length - 1].style.textAlign).toBe('right'); + }); + it('should not render `labels`', async () => { setup(); diff --git a/public/app/features/explore/Logs/LogsTable.tsx b/public/app/features/explore/Logs/LogsTable.tsx index 37ad7591032..23c78fed2bf 100644 --- a/public/app/features/explore/Logs/LogsTable.tsx +++ b/public/app/features/explore/Logs/LogsTable.tsx @@ -9,6 +9,7 @@ import { DataTransformerConfig, Field, FieldType, + guessFieldTypeForField, LogsSortOrder, sortDataFrame, SplitOpen, @@ -86,6 +87,9 @@ export function LogsTable(props: Props) { // This sets the individual field value as filterable filterable: isFieldFilterable(field, logsFrame?.bodyField.name ?? '', logsFrame?.timeField.name ?? ''), }; + + // If it's a string, then try to guess for a better type for numeric support in viz + field.type = field.type === FieldType.string ? guessFieldTypeForField(field) ?? FieldType.string : field.type; } return frameWithOverrides; diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx index 5c69c16bc2c..f98ecb38cda 100644 --- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx +++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx @@ -1,8 +1,8 @@ +import 'whatwg-fetch'; import { render, screen, waitForElementToBeRemoved, within } from '@testing-library/react'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import React from 'react'; -import 'whatwg-fetch'; import { BrowserRouter } from 'react-router-dom'; import { TestProvider } from 'test/helpers/TestProvider'; import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock'; @@ -60,10 +60,13 @@ const paginationResponse: Omit - res(ctx.status(200), ctx.json({ ...paginationResponse, publicDashboards: publicDashboardListResponse })) + http.get('/api/dashboards/public-dashboards', () => + HttpResponse.json({ + ...paginationResponse, + publicDashboards: publicDashboardListResponse, + }) ), - rest.delete('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', (_, res, ctx) => res(ctx.status(200))) + http.delete('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', () => HttpResponse.json({})) ); jest.mock('@grafana/runtime', () => ({ @@ -122,8 +125,8 @@ describe('Show table', () => { }; server.use( - rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => { - return res(ctx.status(200), ctx.json(emptyListRS)); + http.get('/api/dashboards/public-dashboards', () => { + return HttpResponse.json(emptyListRS); }) ); @@ -171,8 +174,8 @@ describe('Orphaned public dashboard', () => { publicDashboards: [...publicDashboardListResponse, ...orphanedDashboardListResponse], }; server.use( - rest.get('/api/dashboards/public-dashboards', (req, res, ctx) => { - return res(ctx.status(200), ctx.json(response)); + http.get('/api/dashboards/public-dashboards', () => { + return HttpResponse.json(response); }) ); jest.spyOn(contextSrv, 'hasPermission').mockReturnValue(true); diff --git a/public/app/features/plugins/admin/__mocks__/catalogPlugin.mock.ts b/public/app/features/plugins/admin/__mocks__/catalogPlugin.mock.ts index e4c8ffb510f..e4c0bf11c3d 100644 --- a/public/app/features/plugins/admin/__mocks__/catalogPlugin.mock.ts +++ b/public/app/features/plugins/admin/__mocks__/catalogPlugin.mock.ts @@ -11,6 +11,7 @@ export default { small: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.2.2/logos/small', large: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.2.2/logos/large', }, + keywords: ['zabbix', 'monitoring', 'dashboard'], }, isCore: false, isDev: false, diff --git a/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts b/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts index 1ea0ed50654..d716ae4df5b 100644 --- a/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts +++ b/public/app/features/plugins/admin/__mocks__/remotePlugin.mock.ts @@ -9,6 +9,7 @@ export default { downloads: 33645089, featured: 180, id: 74, + keywords: ['zabbix', 'monitoring', 'dashboard'], typeId: 1, typeName: 'Application', internal: false, diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx index d88c6e7ab21..512ff968ea0 100644 --- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx +++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx @@ -17,6 +17,7 @@ const plugin: CatalogPlugin = { id: 'test-plugin', info: { logos: { small: '', large: '' }, + keywords: ['test', 'plugin'], }, name: 'Testing Plugin', orgName: 'Test', diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx index d06268248d7..eda80c9c822 100644 --- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx +++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx @@ -15,6 +15,7 @@ const plugin: CatalogPlugin = { id: 'test-plugin', info: { logos: { small: '', large: '' }, + keywords: ['test', 'plugin'], }, name: 'Testing Plugin', orgName: 'Test', diff --git a/public/app/features/plugins/admin/components/PluginList.test.tsx b/public/app/features/plugins/admin/components/PluginList.test.tsx index 45f153a71a4..72218c02660 100644 --- a/public/app/features/plugins/admin/components/PluginList.test.tsx +++ b/public/app/features/plugins/admin/components/PluginList.test.tsx @@ -32,6 +32,7 @@ const getMockPlugin = (id: string): CatalogPlugin => { small: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/small', large: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/large', }, + keywords: ['test', 'plugin'], }, name: 'Testing Plugin', orgName: 'Test', diff --git a/public/app/features/plugins/admin/components/PluginListItem.test.tsx b/public/app/features/plugins/admin/components/PluginListItem.test.tsx index dbb5bbb50a8..c4d42d615ab 100644 --- a/public/app/features/plugins/admin/components/PluginListItem.test.tsx +++ b/public/app/features/plugins/admin/components/PluginListItem.test.tsx @@ -42,6 +42,7 @@ describe('PluginListItem', () => { small: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/small', large: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/large', }, + keywords: ['test', 'plugin'], }, name: 'Testing Plugin', orgName: 'Test', diff --git a/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx b/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx index e6906d72874..f1a86adc691 100644 --- a/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx +++ b/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx @@ -18,6 +18,7 @@ describe('PluginListItemBadges', () => { small: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/small', large: 'https://grafana.com/api/plugins/test-plugin/versions/0.0.10/logos/large', }, + keywords: ['test', 'plugin'], }, name: 'Testing Plugin', orgName: 'Test', diff --git a/public/app/features/plugins/admin/helpers.test.ts b/public/app/features/plugins/admin/helpers.test.ts index 219b3c10403..faef81ce920 100644 --- a/public/app/features/plugins/admin/helpers.test.ts +++ b/public/app/features/plugins/admin/helpers.test.ts @@ -140,6 +140,7 @@ describe('Plugins/Helpers', () => { large: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.1.5/logos/large', small: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.1.5/logos/small', }, + keywords: ['zabbix', 'monitoring', 'dashboard'], }, error: undefined, isCore: false, @@ -266,6 +267,7 @@ describe('Plugins/Helpers', () => { small: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.1.5/logos/small', large: 'https://grafana.com/api/plugins/alexanderzobnin-zabbix-app/versions/4.1.5/logos/large', }, + keywords: ['zabbix', 'monitoring', 'dashboard'], }, error: undefined, isCore: false, diff --git a/public/app/features/plugins/admin/helpers.ts b/public/app/features/plugins/admin/helpers.ts index c5533d33b8b..621d342b626 100644 --- a/public/app/features/plugins/admin/helpers.ts +++ b/public/app/features/plugins/admin/helpers.ts @@ -1,3 +1,5 @@ +import uFuzzy from '@leeoniya/ufuzzy'; + import { PluginSignatureStatus, dateTimeParse, PluginError, PluginType, PluginErrorCode } from '@grafana/data'; import { config, featureEnabled } from '@grafana/runtime'; import configCore, { Settings } from 'app/core/config'; @@ -86,6 +88,7 @@ export function mapRemoteToCatalog(plugin: RemotePlugin, error?: PluginError): C createdAt: publishedAt, status, angularDetected, + keywords, } = plugin; const isDisabled = !!error || isDisabledSecretsPlugin(typeCode); @@ -98,6 +101,7 @@ export function mapRemoteToCatalog(plugin: RemotePlugin, error?: PluginError): C small: `https://grafana.com/api/plugins/${id}/versions/${version}/logos/small`, large: `https://grafana.com/api/plugins/${id}/versions/${version}/logos/large`, }, + keywords, }, name, orgName, @@ -123,7 +127,7 @@ export function mapRemoteToCatalog(plugin: RemotePlugin, error?: PluginError): C export function mapLocalToCatalog(plugin: LocalPlugin, error?: PluginError): CatalogPlugin { const { name, - info: { description, version, logos, updated, author }, + info: { description, version, logos, updated, author, keywords }, id, dev, type, @@ -140,7 +144,7 @@ export function mapLocalToCatalog(plugin: LocalPlugin, error?: PluginError): Cat description, downloads: 0, id, - info: { logos }, + info: { logos, keywords }, name, orgName: author.name, popularity: 0, @@ -173,6 +177,7 @@ export function mapToCatalogPlugin(local?: LocalPlugin, remote?: RemotePlugin, e const id = remote?.slug || local?.id || ''; const type = local?.type || remote?.typeCode; const isDisabled = !!error || isDisabledSecretsPlugin(type); + const keywords = remote?.keywords || local?.info.keywords || []; let logos = { small: `/public/img/icn-${type}.svg`, @@ -195,6 +200,7 @@ export function mapToCatalogPlugin(local?: LocalPlugin, remote?: RemotePlugin, e id, info: { logos, + keywords, }, isCore: Boolean(remote?.internal || local?.signature === PluginSignatureStatus.internal), isDev: Boolean(local?.dev), @@ -345,3 +351,26 @@ function isDisabledSecretsPlugin(type?: PluginType): boolean { export function isLocalCorePlugin(local?: LocalPlugin): boolean { return Boolean(local?.signature === 'internal'); } + +function getId(inputString: string): string { + const parts = inputString.split(' - '); + return parts[0]; +} + +function getPluginDetailsForFuzzySearch(plugins: CatalogPlugin[]): string[] { + return plugins.reduce((result: string[], { id, name, type, orgName, info }: CatalogPlugin) => { + const keywordsForSearch = info.keywords?.join(' ').toLowerCase(); + const pluginString = `${id} - ${name} - ${type} - ${orgName} - ${keywordsForSearch}`; + result.push(pluginString); + return result; + }, []); +} +export function filterByKeyword(plugins: CatalogPlugin[], query: string) { + const dataArray = getPluginDetailsForFuzzySearch(plugins); + let uf = new uFuzzy({}); + let idxs = uf.filter(dataArray, query); + if (idxs === null) { + return null; + } + return idxs.map((id) => getId(dataArray[id])); +} diff --git a/public/app/features/plugins/admin/pages/Browse.test.tsx b/public/app/features/plugins/admin/pages/Browse.test.tsx index a10d57508ab..a22f98e6c2c 100644 --- a/public/app/features/plugins/admin/pages/Browse.test.tsx +++ b/public/app/features/plugins/admin/pages/Browse.test.tsx @@ -183,13 +183,19 @@ describe('Browse list of plugins', () => { describe('when searching', () => { it('should only list plugins matching search', async () => { - const { queryByText } = renderBrowse('/plugins?filterBy=all&q=zabbix', [ - getCatalogPluginMock({ id: 'zabbix', name: 'Zabbix' }), - getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2' }), - getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3' }), + const { queryByText } = renderBrowse('/plugins?filterBy=all&q=matches', [ + getCatalogPluginMock({ id: 'matches-the-search', name: 'Matches the search' }), + getCatalogPluginMock({ + id: 'plugin-2', + name: 'Plugin 2', + }), + getCatalogPluginMock({ + id: 'plugin-3', + name: 'Plugin 3', + }), ]); - await waitFor(() => expect(queryByText('Zabbix')).toBeInTheDocument()); + await waitFor(() => expect(queryByText('Matches the search')).toBeInTheDocument()); // Other plugin types shouldn't be shown expect(queryByText('Plugin 2')).not.toBeInTheDocument(); diff --git a/public/app/features/plugins/admin/pages/Browse.tsx b/public/app/features/plugins/admin/pages/Browse.tsx index 9ec3179e834..195ec0e7b58 100644 --- a/public/app/features/plugins/admin/pages/Browse.tsx +++ b/public/app/features/plugins/admin/pages/Browse.tsx @@ -39,6 +39,7 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem }, sortBy ); + const filterByOptions = [ { value: 'all', label: 'All' }, { value: 'installed', label: 'Installed' }, diff --git a/public/app/features/plugins/admin/state/selectors.ts b/public/app/features/plugins/admin/state/selectors.ts index 2bf3f32de31..5d4188c3792 100644 --- a/public/app/features/plugins/admin/state/selectors.ts +++ b/public/app/features/plugins/admin/state/selectors.ts @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { PluginError, PluginType, unEscapeStringFromRegex } from '@grafana/data'; +import { filterByKeyword } from '../helpers'; import { RequestStatus, PluginCatalogStoreState } from '../types'; import { pluginsAdapter } from './reducer'; @@ -32,11 +33,14 @@ export type PluginFilters = { export const selectPlugins = (filters: PluginFilters) => createSelector(selectAll, (plugins) => { const keyword = filters.keyword ? unEscapeStringFromRegex(filters.keyword.toLowerCase()) : ''; + const filteredPluginIds = keyword !== '' ? filterByKeyword(plugins, keyword) : null; return plugins.filter((plugin) => { - const fieldsToSearchIn = [plugin.name, plugin.orgName].filter(Boolean).map((f) => f.toLowerCase()); + if (keyword && filteredPluginIds == null) { + return false; + } - if (keyword && !fieldsToSearchIn.some((f) => f.includes(keyword))) { + if (keyword && !filteredPluginIds?.includes(plugin.id)) { return false; } diff --git a/public/app/features/plugins/admin/types.ts b/public/app/features/plugins/admin/types.ts index d359d1ffaf1..d74c0808104 100644 --- a/public/app/features/plugins/admin/types.ts +++ b/public/app/features/plugins/admin/types.ts @@ -83,6 +83,7 @@ export interface CatalogPluginInfo { large: string; small: string; }; + keywords: string[]; } export type RemotePlugin = { @@ -93,6 +94,7 @@ export type RemotePlugin = { featured: number; id: number; internal: boolean; + keywords: string[]; json?: { dependencies: PluginDependencies; iam?: IdentityAccessManagement; @@ -161,6 +163,7 @@ export type LocalPlugin = WithAccessControlMetadata & { small: string; large: string; }; + keywords: string[]; build: Build; screenshots?: Array<{ path: string; diff --git a/public/app/features/plugins/loader/pluginLoader.mock.ts b/public/app/features/plugins/loader/pluginLoader.mock.ts index 530b245a592..c683090ad6c 100644 --- a/public/app/features/plugins/loader/pluginLoader.mock.ts +++ b/public/app/features/plugins/loader/pluginLoader.mock.ts @@ -1,4 +1,5 @@ -import { rest } from 'msw'; +import 'whatwg-fetch'; +import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; export const mockSystemModule = `System.register(['./dependencyA'], function (_export, _context) { @@ -85,38 +86,104 @@ export const mockModuleWithDefineMethod = `ace.define(function() { });`; const server = setupServer( - rest.get('/public/plugins/mockAmdModule/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModule)) + http.get( + '/public/plugins/mockAmdModule/module.js', + () => + new HttpResponse(mockAmdModule, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockSystemModule/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockSystemModule)) + http.get( + '/public/plugins/mockSystemModule/module.js', + () => + new HttpResponse(mockSystemModule, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('http://my-cdn.com/plugins/my-plugin/v1.0.0/public/plugins/my-plugin/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModule)) + http.get( + 'http://my-cdn.com/plugins/my-plugin/v1.0.0/public/plugins/my-plugin/module.js', + () => + new HttpResponse(mockAmdModule, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleNamedNoDeps/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleNamedNoDeps)) + http.get( + '/public/plugins/mockAmdModuleNamedNoDeps/module.js', + () => + new HttpResponse(mockAmdModuleNamedNoDeps, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleNamedWithDeps/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleNamedWithDeps)) + http.get( + '/public/plugins/mockAmdModuleNamedWithDeps/module.js', + () => + new HttpResponse(mockAmdModuleNamedWithDeps, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleNamedWithDeps2/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleNamedWithDeps2)) + http.get( + '/public/plugins/mockAmdModuleNamedWithDeps2/module.js', + () => + new HttpResponse(mockAmdModuleNamedWithDeps2, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleNamedWithDeps3/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleNamedWithDeps3)) + http.get( + '/public/plugins/mockAmdModuleNamedWithDeps3/module.js', + () => + new HttpResponse(mockAmdModuleNamedWithDeps3, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleOnlyFunction/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleOnlyFunction)) + http.get( + '/public/plugins/mockAmdModuleOnlyFunction/module.js', + () => + new HttpResponse(mockAmdModuleOnlyFunction, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleWithComments/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleWithComments)) + http.get( + '/public/plugins/mockAmdModuleWithComments/module.js', + () => + new HttpResponse(mockAmdModuleWithComments, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockAmdModuleWithComments2/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockAmdModuleWithComments2)) + http.get( + '/public/plugins/mockAmdModuleWithComments2/module.js', + () => + new HttpResponse(mockAmdModuleWithComments2, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ), - rest.get('/public/plugins/mockModuleWithDefineMethod/module.js', async (_req, res, ctx) => - res(ctx.status(200), ctx.set('Content-Type', 'text/javascript'), ctx.body(mockModuleWithDefineMethod)) + http.get( + '/public/plugins/mockModuleWithDefineMethod/module.js', + () => + new HttpResponse(mockModuleWithDefineMethod, { + headers: { + 'Content-Type': 'text/javascript', + }, + }) ) ); diff --git a/public/app/features/plugins/loader/systemjsHooks.test.ts b/public/app/features/plugins/loader/systemjsHooks.test.ts index 08d33e2c644..9cd499b0c04 100644 --- a/public/app/features/plugins/loader/systemjsHooks.test.ts +++ b/public/app/features/plugins/loader/systemjsHooks.test.ts @@ -28,11 +28,13 @@ describe('SystemJS Loader Hooks', () => { const originalFetch = systemJSPrototype.fetch; const originalResolve = systemJSPrototype.resolve; - systemJSPrototype.resolve = (moduleId: string) => moduleId; - systemJSPrototype.shouldFetch = () => true; - beforeAll(() => { server.listen(); + systemJSPrototype.resolve = (moduleId: string) => moduleId; + systemJSPrototype.shouldFetch = () => true; + // because server.listen() patches fetch, we need to reassign this to the systemJSPrototype + // this is identical to what happens in the original code: https://github.com/systemjs/systemjs/blob/main/src/features/fetch-load.js#L12 + systemJSPrototype.fetch = window.fetch; }); afterEach(() => server.resetHandlers()); afterAll(() => { @@ -43,7 +45,11 @@ describe('SystemJS Loader Hooks', () => { describe('decorateSystemJSFetch', () => { it('wraps AMD modules in an AMD iife', async () => { - const basicResult = await decorateSystemJSFetch(originalFetch, '/public/plugins/mockAmdModule/module.js', {}); + const basicResult = await decorateSystemJSFetch( + systemJSPrototype.fetch, + '/public/plugins/mockAmdModule/module.js', + {} + ); const basicSource = await basicResult.text(); const basicExpected = `(function(define) { ${mockAmdModule} @@ -51,7 +57,7 @@ describe('SystemJS Loader Hooks', () => { expect(basicSource).toBe(basicExpected); const mockAmdModuleNamedNoDepsResult = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleNamedNoDeps/module.js', {} ); @@ -63,7 +69,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleNamedNoDepsSource).toBe(mockAmdModuleNamedNoDepsExpected); const mockAmdModuleNamedWithDepsResult = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleNamedWithDeps/module.js', {} ); @@ -75,7 +81,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleNamedWithDepsSource).toBe(mockAmdModuleNamedWithDepsExpected); const mockAmdModuleNamedWithDeps2Result = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleNamedWithDeps2/module.js', {} ); @@ -87,7 +93,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleNamedWithDeps2Source).toBe(mockAmdModuleNamedWithDeps2Expected); const mockAmdModuleNamedWithDeps3Result = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleNamedWithDeps3/module.js', {} ); @@ -99,7 +105,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleNamedWithDeps3Source).toBe(mockAmdModuleNamedWithDeps3Expected); const mockAmdModuleOnlyFunctionResult = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleOnlyFunction/module.js', {} ); @@ -111,7 +117,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleOnlyFunctionSource).toBe(mockAmdModuleOnlyFunctionExpected); const mockAmdModuleWithCommentsResult = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleWithComments/module.js', {} ); @@ -123,7 +129,7 @@ describe('SystemJS Loader Hooks', () => { expect(mockAmdModuleWithCommentsSource).toBe(mockAmdModuleWithCommentsExpected); const mockAmdModuleWithComments2Result = await decorateSystemJSFetch( - originalFetch, + systemJSPrototype.fetch, '/public/plugins/mockAmdModuleWithComments2/module.js', {} ); @@ -136,14 +142,14 @@ describe('SystemJS Loader Hooks', () => { }); it("doesn't wrap system modules in an AMD iife", async () => { const url = '/public/plugins/mockSystemModule/module.js'; - const result = await decorateSystemJSFetch(originalFetch, url, {}); + const result = await decorateSystemJSFetch(systemJSPrototype.fetch, url, {}); const source = await result.text(); expect(source).toBe(mockSystemModule); }); it("doesn't wrap modules with a define method in an AMD iife", async () => { const url = '/public/plugins/mockModuleWithDefineMethod/module.js'; - const result = await decorateSystemJSFetch(originalFetch, url, {}); + const result = await decorateSystemJSFetch(systemJSPrototype.fetch, url, {}); const source = await result.text(); expect(source).toBe(mockModuleWithDefineMethod); @@ -151,13 +157,13 @@ describe('SystemJS Loader Hooks', () => { it('only transforms plugin source code hosted on cdn with cdn paths', async () => { config.pluginsCDNBaseURL = 'http://my-cdn.com/plugins'; const cdnUrl = 'http://my-cdn.com/plugins/my-plugin/v1.0.0/public/plugins/my-plugin/module.js'; - const cdnResult = await decorateSystemJSFetch(originalFetch, cdnUrl, {}); + const cdnResult = await decorateSystemJSFetch(systemJSPrototype.fetch, cdnUrl, {}); const cdnSource = await cdnResult.text(); expect(cdnSource).toContain('var pluginPath = "http://my-cdn.com/plugins/my-plugin/v1.0.0/public/plugins/";'); const url = '/public/plugins/mockAmdModule/module.js'; - const result = await decorateSystemJSFetch(originalFetch, url, {}); + const result = await decorateSystemJSFetch(systemJSPrototype.fetch, url, {}); const source = await result.text(); expect(source).toContain('var pluginPath = "/public/plugins/";'); }); diff --git a/public/test/jest-resolver.js b/public/test/jest-resolver.js index 75b29ad00dc..40046b872d5 100644 --- a/public/test/jest-resolver.js +++ b/public/test/jest-resolver.js @@ -27,6 +27,23 @@ module.exports = (path, options) => { delete pkg['exports']; delete pkg['module']; } + // Jest + jsdom acts like a browser (i.e., it looks for "browser" imports + // under pkg.exports), but msw knows that you're operating in a Node + // environment: + // + // https://github.com/mswjs/msw/issues/1786#issuecomment-1782559851 + // + // The MSW project's recommended workaround is to disable Jest's + // customExportConditions completely, so no packages use their browser's + // versions. We'll instead clear export conditions only for MSW. + // + // Taken from https://github.com/mswjs/msw/issues/1786#issuecomment-1787730599 + if (pkg.name === 'msw') { + delete pkg.exports['./node'].browser; + } + if (pkg.name === '@mswjs/interceptors') { + delete pkg.exports; + } return pkg; }, }); diff --git a/yarn.lock b/yarn.lock index 716b2cb10e7..a7d0f3b5995 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1896,6 +1896,24 @@ __metadata: languageName: node linkType: hard +"@bundled-es-modules/cookie@npm:^2.0.0": + version: 2.0.0 + resolution: "@bundled-es-modules/cookie@npm:2.0.0" + dependencies: + cookie: "npm:^0.5.0" + checksum: 10/c8ef02aa5d3f6c786cfa407e1c93b4af29c600eb09990973f47a7a49e4771c1bec37c8f8e567638bb9cbc41f4e38d065ff1d8eaf9bf91f0c3613a6d60bc82c8c + languageName: node + linkType: hard + +"@bundled-es-modules/statuses@npm:^1.0.1": + version: 1.0.1 + resolution: "@bundled-es-modules/statuses@npm:1.0.1" + dependencies: + statuses: "npm:^2.0.1" + checksum: 10/9bf6a2bcf040a66fb805da0e1446041fd9def7468bb5da29c5ce02adf121a3f7cec123664308059a62a46fcaee666add83094b76df6dce72e5cafa8e6bebe60d + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -4340,6 +4358,45 @@ __metadata: languageName: node linkType: hard +"@inquirer/confirm@npm:^3.0.0": + version: 3.0.0 + resolution: "@inquirer/confirm@npm:3.0.0" + dependencies: + "@inquirer/core": "npm:^7.0.0" + "@inquirer/type": "npm:^1.2.0" + checksum: 10/ed16dc0e5b22115474853ca57dbe3dacdcd15bcb37cc50020e8e76ff8d0875d62d8b63b93b3092c653faeb6c83a139eac997ff05638b0f1f78ae919f29ee29d4 + languageName: node + linkType: hard + +"@inquirer/core@npm:^7.0.0": + version: 7.0.0 + resolution: "@inquirer/core@npm:7.0.0" + dependencies: + "@inquirer/type": "npm:^1.2.0" + "@types/mute-stream": "npm:^0.0.4" + "@types/node": "npm:^20.11.16" + "@types/wrap-ansi": "npm:^3.0.0" + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^4.1.2" + cli-spinners: "npm:^2.9.2" + cli-width: "npm:^4.1.0" + figures: "npm:^3.2.0" + mute-stream: "npm:^1.0.0" + run-async: "npm:^3.0.0" + signal-exit: "npm:^4.1.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^6.2.0" + checksum: 10/78c0ef4bb82cb7be23f16a80c9cff02839c77e378d272327f49878788a4c3b1cc00137387317053d242a87634954850a4d2546b3e48b1abd27130a21f598afef + languageName: node + linkType: hard + +"@inquirer/type@npm:^1.2.0": + version: 1.2.0 + resolution: "@inquirer/type@npm:1.2.0" + checksum: 10/12f68a16d8995efb409bd243d6ccc501b366e8009630a075071a9d9497cebd36bbd6c46d7d59b37435629e5e50236394679f414f7676b68b913ecc28a85cba0a + languageName: node + linkType: hard + "@internationalized/date@npm:^3.5.1": version: 3.5.1 resolution: "@internationalized/date@npm:3.5.1" @@ -5207,6 +5264,13 @@ __metadata: languageName: node linkType: hard +"@mswjs/cookies@npm:^1.1.0": + version: 1.1.0 + resolution: "@mswjs/cookies@npm:1.1.0" + checksum: 10/168ed1966e579a4f454e6d2af5a015150cca570ac4c660f5b656e7bc021afacbf0b3d4ed3d03e9293550f3965c28ce1e293fa7037c6cf46ed7e268e21a1053a4 + languageName: node + linkType: hard + "@mswjs/interceptors@npm:^0.17.10": version: 0.17.10 resolution: "@mswjs/interceptors@npm:0.17.10" @@ -5223,6 +5287,20 @@ __metadata: languageName: node linkType: hard +"@mswjs/interceptors@npm:^0.25.16": + version: 0.25.16 + resolution: "@mswjs/interceptors@npm:0.25.16" + dependencies: + "@open-draft/deferred-promise": "npm:^2.2.0" + "@open-draft/logger": "npm:^0.3.0" + "@open-draft/until": "npm:^2.0.0" + is-node-process: "npm:^1.2.0" + outvariant: "npm:^1.2.1" + strict-event-emitter: "npm:^0.5.1" + checksum: 10/d8fb74db45a63971e9da7367c8d120343c8f49fec7bcc3f0c77c04c3f628d307b70875f52e4a99df561547b92d0d53edacc421e42d69940d44999254b5d028b5 + languageName: node + linkType: hard + "@ndelangen/get-tarball@npm:^3.0.7": version: 3.0.7 resolution: "@ndelangen/get-tarball@npm:3.0.7" @@ -5655,6 +5733,23 @@ __metadata: languageName: node linkType: hard +"@open-draft/deferred-promise@npm:^2.2.0": + version: 2.2.0 + resolution: "@open-draft/deferred-promise@npm:2.2.0" + checksum: 10/bc3bb1668a555bb87b33383cafcf207d9561e17d2ca0d9e61b7ce88e82b66e36a333d3676c1d39eb5848022c03c8145331fcdc828ba297f88cb1de9c5cef6c19 + languageName: node + linkType: hard + +"@open-draft/logger@npm:^0.3.0": + version: 0.3.0 + resolution: "@open-draft/logger@npm:0.3.0" + dependencies: + is-node-process: "npm:^1.2.0" + outvariant: "npm:^1.4.0" + checksum: 10/7a280f170bcd4e91d3eedbefe628efd10c3bd06dd2461d06a7fdbced89ef457a38785847f88cc630fb4fd7dfa176d6f77aed17e5a9b08000baff647433b5ff78 + languageName: node + linkType: hard + "@open-draft/until@npm:^1.0.3": version: 1.0.3 resolution: "@open-draft/until@npm:1.0.3" @@ -5662,6 +5757,13 @@ __metadata: languageName: node linkType: hard +"@open-draft/until@npm:^2.0.0, @open-draft/until@npm:^2.1.0": + version: 2.1.0 + resolution: "@open-draft/until@npm:2.1.0" + checksum: 10/622be42950afc8e89715d0fd6d56cbdcd13e36625e23b174bd3d9f06f80e25f9adf75d6698af93bca1e1bf465b9ce00ec05214a12189b671fb9da0f58215b6f4 + languageName: node + linkType: hard + "@opentelemetry/api-logs@npm:0.45.1": version: 0.45.1 resolution: "@opentelemetry/api-logs@npm:0.45.1" @@ -8750,6 +8852,13 @@ __metadata: languageName: node linkType: hard +"@types/cookie@npm:^0.6.0": + version: 0.6.0 + resolution: "@types/cookie@npm:0.6.0" + checksum: 10/b883348d5bf88695fbc2c2276b1c49859267a55cae3cf11ea1dccc1b3be15b466e637ce3242109ba27d616c77c6aa4efe521e3d557110b4fdd9bc332a12445c2 + languageName: node + linkType: hard + "@types/cross-spawn@npm:^6.0.2": version: 6.0.3 resolution: "@types/cross-spawn@npm:6.0.3" @@ -9532,6 +9641,15 @@ __metadata: languageName: node linkType: hard +"@types/mute-stream@npm:^0.0.4": + version: 0.0.4 + resolution: "@types/mute-stream@npm:0.0.4" + dependencies: + "@types/node": "npm:*" + checksum: 10/af8d83ad7b68ea05d9357985daf81b6c9b73af4feacb2f5c2693c7fd3e13e5135ef1bd083ce8d5bdc8e97acd28563b61bb32dec4e4508a8067fcd31b8a098632 + languageName: node + linkType: hard + "@types/node-fetch@npm:^2.6.4": version: 2.6.4 resolution: "@types/node-fetch@npm:2.6.4" @@ -9567,7 +9685,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:20.11.17": +"@types/node@npm:20.11.17, @types/node@npm:^20.11.16": version: 20.11.17 resolution: "@types/node@npm:20.11.17" dependencies: @@ -9986,6 +10104,13 @@ __metadata: languageName: node linkType: hard +"@types/statuses@npm:^2.0.4": + version: 2.0.4 + resolution: "@types/statuses@npm:2.0.4" + checksum: 10/3a806c3b96d1845e3e7441fbf0839037e95f717334760ddb7c29223c9a34a7206b68e2998631f89f1a1e3ef5b67b15652f6e8fa14987ebd7f6d38587c1bffd18 + languageName: node + linkType: hard + "@types/string-hash@npm:1.1.3": version: 1.1.3 resolution: "@types/string-hash@npm:1.1.3" @@ -10090,6 +10215,13 @@ __metadata: languageName: node linkType: hard +"@types/wrap-ansi@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/wrap-ansi@npm:3.0.0" + checksum: 10/8aa644946ca4e859668c36b8e2bcf2ac4bdee59dac760414730ea57be8a93ae9166ebd40a088f2ab714843aaea2a2a67f0e6e6ec11cfc9c8701b2466ca1c4089 + languageName: node + linkType: hard + "@types/ws@npm:^8.5.5": version: 8.5.5 resolution: "@types/ws@npm:8.5.5" @@ -13023,6 +13155,13 @@ __metadata: languageName: node linkType: hard +"cli-spinners@npm:^2.9.2": + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 10/a0a863f442df35ed7294424f5491fa1756bd8d2e4ff0c8736531d886cec0ece4d85e8663b77a5afaf1d296e3cbbebff92e2e99f52bbea89b667cbe789b994794 + languageName: node + linkType: hard + "cli-table3@npm:^0.6.1, cli-table3@npm:~0.6.1": version: 0.6.3 resolution: "cli-table3@npm:0.6.3" @@ -13053,6 +13192,13 @@ __metadata: languageName: node linkType: hard +"cli-width@npm:^4.1.0": + version: 4.1.0 + resolution: "cli-width@npm:4.1.0" + checksum: 10/b58876fbf0310a8a35c79b72ecfcf579b354e18ad04e6b20588724ea2b522799a758507a37dfe132fafaf93a9922cafd9514d9e1598e6b2cd46694853aed099f + languageName: node + linkType: hard + "cliui@npm:^7.0.2": version: 7.0.4 resolution: "cliui@npm:7.0.4" @@ -13637,6 +13783,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^0.5.0": + version: 0.5.0 + resolution: "cookie@npm:0.5.0" + checksum: 10/aae7911ddc5f444a9025fbd979ad1b5d60191011339bce48e555cb83343d0f98b865ff5c4d71fecdfb8555a5cafdc65632f6fce172f32aaf6936830a883a0380 + languageName: node + linkType: hard + "copy-to-clipboard@npm:^3.3.1": version: 3.3.1 resolution: "copy-to-clipboard@npm:3.3.1" @@ -18470,7 +18623,7 @@ __metadata: mousetrap: "npm:1.6.5" mousetrap-global-bind: "npm:1.1.0" moveable: "npm:0.53.0" - msw: "npm:1.3.2" + msw: "npm:2.2.0" mutationobserver-shim: "npm:0.3.7" nanoid: "npm:^5.0.4" ngtemplate-loader: "npm:2.1.0" @@ -18805,6 +18958,13 @@ __metadata: languageName: node linkType: hard +"headers-polyfill@npm:^4.0.2": + version: 4.0.2 + resolution: "headers-polyfill@npm:4.0.2" + checksum: 10/70b53abf48a1d50760150624d6c7ca974a0d286ba102e411538f6dad6687ce51ce7cc60197e326df96f844548d6ff77d900e28c3cdbc0ba1fe09a05eae47156a + languageName: node + linkType: hard + "heimdalljs-logger@npm:^0.1.10, heimdalljs-logger@npm:^0.1.7": version: 0.1.10 resolution: "heimdalljs-logger@npm:0.1.10" @@ -23005,6 +23165,38 @@ __metadata: languageName: node linkType: hard +"msw@npm:2.2.0": + version: 2.2.0 + resolution: "msw@npm:2.2.0" + dependencies: + "@bundled-es-modules/cookie": "npm:^2.0.0" + "@bundled-es-modules/statuses": "npm:^1.0.1" + "@inquirer/confirm": "npm:^3.0.0" + "@mswjs/cookies": "npm:^1.1.0" + "@mswjs/interceptors": "npm:^0.25.16" + "@open-draft/until": "npm:^2.1.0" + "@types/cookie": "npm:^0.6.0" + "@types/statuses": "npm:^2.0.4" + chalk: "npm:^4.1.2" + graphql: "npm:^16.8.1" + headers-polyfill: "npm:^4.0.2" + is-node-process: "npm:^1.2.0" + outvariant: "npm:^1.4.2" + path-to-regexp: "npm:^6.2.0" + strict-event-emitter: "npm:^0.5.1" + type-fest: "npm:^4.9.0" + yargs: "npm:^17.7.2" + peerDependencies: + typescript: ">= 4.7.x <= 5.3.x" + peerDependenciesMeta: + typescript: + optional: true + bin: + msw: cli/index.js + checksum: 10/36e6a1f0bc89d1c84bf24c1cf7ca7c3fe5d5b032c825d52a832e9b815830976a86c17a8c3f1f506db720f44e99d04c9302e014cf569b51b2d2af62562a9fe62a + languageName: node + linkType: hard + "multicast-dns@npm:^7.2.4": version: 7.2.4 resolution: "multicast-dns@npm:7.2.4" @@ -23044,7 +23236,7 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:~1.0.0": +"mute-stream@npm:^1.0.0, mute-stream@npm:~1.0.0": version: 1.0.0 resolution: "mute-stream@npm:1.0.0" checksum: 10/36fc968b0e9c9c63029d4f9dc63911950a3bdf55c9a87f58d3a266289b67180201cade911e7699f8b2fa596b34c9db43dad37649e3f7fdd13c3bb9edb0017ee7 @@ -23940,10 +24132,10 @@ __metadata: languageName: node linkType: hard -"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0": - version: 1.4.0 - resolution: "outvariant@npm:1.4.0" - checksum: 10/07b9bcb9b3a2ff1b3db02af6b07d70e663082b30ddc08ff475d7c85fc623fdcc4433a4ab5b88f6902b62dbb284eef1be386aa537e14cef0519fad887ec483054 +"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2": + version: 1.4.2 + resolution: "outvariant@npm:1.4.2" + checksum: 10/f16ba035fb65d1cbe7d2e06693dd42183c46bc8456713d9ddb5182d067defa7d78217edab0a2d3e173d3bacd627b2bd692195c7087c225b82548fbf52c677b38 languageName: node linkType: hard @@ -27670,6 +27862,13 @@ __metadata: languageName: node linkType: hard +"run-async@npm:^3.0.0": + version: 3.0.0 + resolution: "run-async@npm:3.0.0" + checksum: 10/97fb8747f7765b77ebcd311d3a33548099336f04c6434e0763039b98c1de0f1b4421000695aff8751f309c0b995d8dfd620c1f1e4c35572da38c101488165305 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -28113,6 +28312,13 @@ __metadata: languageName: node linkType: hard +"signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f + languageName: node + linkType: hard + "sigstore@npm:^1.4.0": version: 1.9.0 resolution: "sigstore@npm:1.9.0" @@ -28792,6 +28998,13 @@ __metadata: languageName: node linkType: hard +"statuses@npm:^2.0.1": + version: 2.0.1 + resolution: "statuses@npm:2.0.1" + checksum: 10/18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb + languageName: node + linkType: hard + "std-env@npm:^3.6.0": version: 3.7.0 resolution: "std-env@npm:3.7.0" @@ -28941,6 +29154,13 @@ __metadata: languageName: node linkType: hard +"strict-event-emitter@npm:^0.5.1": + version: 0.5.1 + resolution: "strict-event-emitter@npm:0.5.1" + checksum: 10/25c84d88be85940d3547db665b871bfecea4ea0bedfeb22aae8db48126820cfb2b0bc2fba695392592a09b1aa36b686d6eede499e1ecd151593c03fe5a50d512 + languageName: node + linkType: hard + "string-hash@npm:^1.1.3": version: 1.1.3 resolution: "string-hash@npm:1.1.3" @@ -30253,6 +30473,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.9.0": + version: 4.10.2 + resolution: "type-fest@npm:4.10.2" + checksum: 10/2b1ad1270d9fabeeb506ba831d513caeb05bfc852e5e012511d785ce9dc68d773fe0a42bddf857a362c7f3406244809c5b8a698b743bb7617d4a8c470672087f + languageName: node + linkType: hard + "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -31930,7 +32157,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:17.7.2, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2": +"yargs@npm:17.7.2, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: