diff --git a/NOTICE b/NOTICE index 5d9cae4dc11..d0376f0ab76 100644 --- a/NOTICE +++ b/NOTICE @@ -7,9 +7,9 @@ The following 3rd-party software packages may be used by or distributed with gooddata-ui-sdk. Any information relevant to third-party vendors listed below are collected using common, reasonable means. -Date generated: 2026-8-24 +Date generated: 2026-8-26 -Revision ID: b0716addf9b4740b3ab90ad05ec818dc8246ff37 +Revision ID: 801e4736307fbb28cf5d9d0a6566fc45d596c003 ================================================================================ ================================================================================ @@ -272,6 +272,13 @@ No first party licenses found in gooddata-ui-sdk - @peculiar/utils (2.0.3) [MIT] - @peculiar/x509 (1.14.3) [MIT] - @playwright/test (1.62.1) [Apache-2.0] +- @rc-component/motion (1.3.3) [MIT] +- @rc-component/overflow (1.0.1) [MIT] +- @rc-component/picker (1.12.0) [MIT] +- @rc-component/portal (2.2.1) [MIT] +- @rc-component/resize-observer (1.1.2) [MIT] +- @rc-component/trigger (3.10.1) [MIT] +- @rc-component/util (1.12.0) [MIT] - @react-aria/interactions (3.28.1) [Apache-2.0] - @react-dnd/asap (4.0.1) [MIT] - @react-dnd/asap (5.0.2) [MIT] @@ -466,7 +473,7 @@ No first party licenses found in gooddata-ui-sdk - cosmiconfig (9.0.2) [MIT] - cosmiconfig (7.1.0) [MIT] - crelt (1.0.7) [MIT] -- cron-parser (5.6.2) [MIT] +- cron-parser (5.9.0) [MIT] - cross-spawn (7.0.6) [MIT] - css-functions-list (3.3.3) [MIT] - css-mediaquery (0.1.2) [BSD-3-Clause] @@ -543,6 +550,7 @@ No first party licenses found in gooddata-ui-sdk - fast-defer (1.1.9) [MIT] - fast-equals (5.4.1) [MIT] - fast-glob (3.3.3) [MIT] +- fast-json-patch (3.1.1) [MIT] - fast-uri (3.1.4) [BSD-3-Clause, bsd-2-clause-views] - fastest-levenshtein (1.0.16) [MIT] - fastq (1.20.1) [ISC] @@ -656,6 +664,7 @@ No first party licenses found in gooddata-ui-sdk - is-hexadecimal (2.0.1) [MIT] - is-inside-container (1.0.0) [MIT] - is-interactive (1.0.0) [MIT] +- is-mobile (5.0.0) [MIT] - is-network-error (1.3.2) [MIT] - is-number (7.0.0) [MIT] - is-obj (1.0.1) [MIT] @@ -875,6 +884,7 @@ No first party licenses found in gooddata-ui-sdk - react-fast-compare (3.2.2) [MIT] - react-intl (7.1.11) [BSD-3-Clause] - react-is (16.13.1) [MIT] +- react-is (19.2.8) [MIT] - react-lines-ellipsis (0.16.1) [MIT] - react-loading-skeleton (3.5.0) [MIT] - react-markdown (10.1.0) [MIT] @@ -4990,6 +5000,88 @@ This software contains code derived from the Puppeteer project (https://github.c available under the Apache 2.0 license (https://github.com/puppeteer/puppeteer/blob/master/LICENSE). +-------------------------------------------------------------------------------- +Package Title: @rc-component/picker (1.12.0) + +Package Locator: npm+@rc-component/picker$1.12.0 + +Package Depth: Direct +-------------------------------------------------------------------------------- + +React date & time picker + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE + - Copyright (c) 2019 present react-component +- LICENSE.md + - Copyright (c) 2019 present afc163 +- package.json +-------------------------------------------------------------------------------- + +MIT License + +Copyright (c) 2019-present react-component + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* License Header * +MIT License + +Copyright (c) 2019-present react-component + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2019 present react-component +- Copyright (c) 2019 present afc163 + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://react-component.github.io/picker +Package Download URL: https://registry.npmjs.org/@rc-component/picker/-/picker-1.12.0.tgz +Dependency Path: @rc-component/picker +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: @react-aria/interactions (3.28.1) @@ -6879,9 +6971,9 @@ Dependency Path: copy-to-clipboard File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- -Package Title: cron-parser (5.6.2) +Package Title: cron-parser (5.9.0) -Package Locator: npm+cron-parser$5.6.2 +Package Locator: npm+cron-parser$5.9.0 Package Depth: Direct -------------------------------------------------------------------------------- @@ -6953,7 +7045,7 @@ MIT Authors: harri@siirak.ee Package Manager: NPM Project URL: https://github.com/harrisiirak/cron-parser#readme -Package Download URL: https://registry.npmjs.org/cron-parser/-/cron-parser-5.6.2.tgz +Package Download URL: https://registry.npmjs.org/cron-parser/-/cron-parser-5.9.0.tgz Dependency Path: cron-parser File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml @@ -8152,6 +8244,92 @@ Package Download URL: https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz Dependency Path: @formatjs/cli-lib > fast-glob > fast-glob > stylelint > fast-glob > stylelint > globby > fast-glob > stylelint-config-standard > stylelint > fast-glob > stylelint-config-standard > stylelint-config-recommended > stylelint > fast-glob > stylelint-config-standard > stylelint-config-recommended > stylelint > globby > fast-glob > stylelint-order > stylelint > fast-glob > stylelint-plugin-defensive-css > stylelint > fast-glob > stylelint-scss > stylelint > fast-glob File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml +-------------------------------------------------------------------------------- +Package Title: fast-json-patch (3.1.1) + +Package Locator: npm+fast-json-patch$3.1.1 + +Package Depth: Direct +-------------------------------------------------------------------------------- + +Fast implementation of JSON-Patch (RFC-6902) with duplex (observe changes) capabilities + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- dist/fast-json-patch.js + - Copyright (c) 2017 Evgeny Poberezkin +- LICENSE.txt + - Copyright (c) 2013, 2014, 2020 Joachim Wester +- module/core.mjs + - Copyright (c) 2017 Evgeny Poberezkin +- package.json +-------------------------------------------------------------------------------- + +(The MIT License) + +Copyright (c) 2013, 2014, 2020 Joachim Wester + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +(The MIT License) + +Copyright (c) 2013, 2014, 2020 Joachim Wester + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2013, 2014, 2020 Joachim Wester +- Copyright (c) 2017 Evgeny Poberezkin + +* Package Info * + +Authors: joachimwester@me.com, marcin.warpechowski@handsontable.com, omar@omaralshaker.com, tomalecwp@gmail.com +Package Manager: NPM +Project URL: https://github.com/Starcounter-Jack/JSON-Patch +Package Download URL: https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz +Dependency Path: fast-json-patch +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: fs-extra (10.1.0) @@ -11793,7 +11971,7 @@ Authors: opensource+npm@fb.com, react-core@meta.com Package Manager: NPM Project URL: https://react.dev/ Package Download URL: https://registry.npmjs.org/react/-/react-19.1.1.tgz -Dependency Path: @aaronhayes/react-use-hubspot-form > react > @evil-internetmann/react-dnd > react > @floating-ui/react > @floating-ui/react-dom > react > @floating-ui/react > react > @floating-ui/react-dom > react > @react-aria/interactions > @react-types/shared > react > @react-aria/interactions > react > react > react-select > @emotion/react > @emotion/use-insertion-effect-with-fallbacks > react > react-select > @emotion/react > react +Dependency Path: @aaronhayes/react-use-hubspot-form > react > @evil-internetmann/react-dnd > react > @floating-ui/react > @floating-ui/react-dom > react > @floating-ui/react > react > @floating-ui/react-dom > react > @rc-component/picker > @rc-component/overflow > react > @rc-component/picker > @rc-component/trigger > @rc-component/motion > react > react > react-select > @emotion/react > @emotion/use-insertion-effect-with-fallbacks > react > react-select > @emotion/react > react File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- @@ -12185,7 +12363,7 @@ Authors: opensource+npm@fb.com, react-core@meta.com Package Manager: NPM Project URL: https://react.dev/ Package Download URL: https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz -Dependency Path: @aaronhayes/react-use-hubspot-form > react-dom > @floating-ui/react > @floating-ui/react-dom > react-dom > @floating-ui/react > react-dom > @floating-ui/react-dom > react-dom > @react-aria/interactions > react-aria > react-dom > @react-aria/interactions > react-dom > @tanstack/react-virtual > react-dom > ag-grid-react > react-dom > react-dom > react-lines-ellipsis > react-dom +Dependency Path: @aaronhayes/react-use-hubspot-form > react-dom > @floating-ui/react > @floating-ui/react-dom > react-dom > @floating-ui/react > react-dom > @floating-ui/react-dom > react-dom > @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > react-dom > @rc-component/picker > @rc-component/overflow > react-dom > @rc-component/picker > @rc-component/trigger > @rc-component/motion > react-dom > @rc-component/picker > @rc-component/trigger > @rc-component/portal > react-dom > @rc-component/picker > react-dom > react-dom File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- @@ -22358,7 +22536,7 @@ Authors: bng412@gmail.com, hello+npm@nicr.dev, hi@henryzoo.com, jlhwung@gmail.co Package Manager: NPM Project URL: https://babel.dev/docs/en/next/babel-runtime Package Download URL: https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz -Dependency Path: downshift > @babel/runtime > polished > @babel/runtime > react-measure > @babel/runtime > react-select > @babel/runtime > react-select > @emotion/react > @babel/runtime > react-select > @emotion/react > @emotion/babel-plugin > @babel/runtime > react-select > @emotion/react > @emotion/babel-plugin > babel-plugin-macros > @babel/runtime > react-select > react-transition-group > dom-helpers > @babel/runtime > react-textarea-autosize > @babel/runtime > redux-saga > @redux-saga/core > @babel/runtime +Dependency Path: @rc-component/picker > @rc-component/overflow > @babel/runtime > downshift > @babel/runtime > polished > @babel/runtime > react-measure > @babel/runtime > react-select > @babel/runtime > react-select > @emotion/react > @babel/runtime > react-select > @emotion/react > @emotion/babel-plugin > @babel/runtime > react-select > @emotion/react > @emotion/babel-plugin > babel-plugin-macros > @babel/runtime > react-select > react-transition-group > dom-helpers > @babel/runtime > redux-saga > @redux-saga/core > @babel/runtime File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- @@ -26473,6 +26651,276 @@ Package Download URL: https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2. Dependency Path: @formatjs/cli-lib > fast-glob > @nodelib/fs.walk > fast-glob > @nodelib/fs.walk > stylelint > fast-glob > @nodelib/fs.walk > stylelint > globby > fast-glob > @nodelib/fs.walk > stylelint-config-standard > stylelint > fast-glob > @nodelib/fs.walk > stylelint-config-standard > stylelint-config-recommended > stylelint > fast-glob > @nodelib/fs.walk > stylelint-config-standard > stylelint-config-recommended > stylelint > globby > fast-glob > @nodelib/fs.walk > stylelint-order > stylelint > fast-glob > @nodelib/fs.walk > stylelint-plugin-defensive-css > stylelint > fast-glob > @nodelib/fs.walk > stylelint-scss > stylelint > fast-glob > @nodelib/fs.walk File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml +-------------------------------------------------------------------------------- +Package Title: @rc-component/overflow (1.0.1) + +Package Locator: npm+@rc-component/overflow$1.0.1 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Auto collapse box when overflow + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE.md + - Copyright (c) 2019 present afc163 +- package.json +-------------------------------------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2019 present afc163 + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://react-component.github.io/overflow +Package Download URL: https://registry.npmjs.org/@rc-component/overflow/-/overflow-1.0.1.tgz +Dependency Path: @rc-component/picker > @rc-component/overflow +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + +-------------------------------------------------------------------------------- +Package Title: @rc-component/resize-observer (1.1.2) + +Package Locator: npm+@rc-component/resize-observer$1.1.2 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Resize observer for React + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE.md + - Copyright (c) 2019 present afc163 +- package.json +-------------------------------------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2019 present afc163 + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://www.npmjs.com/package/@rc-component/resize-observer +Package Download URL: https://registry.npmjs.org/@rc-component/resize-observer/-/resize-observer-1.1.2.tgz +Dependency Path: @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > @rc-component/picker > @rc-component/resize-observer > @rc-component/picker > @rc-component/trigger > @rc-component/resize-observer +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + +-------------------------------------------------------------------------------- +Package Title: @rc-component/trigger (3.10.1) + +Package Locator: npm+@rc-component/trigger$3.10.1 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Popup trigger and alignment primitive for React. + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE + - Copyright (c) 2015 present Alipay.com, https://www.alipay.com/ +- package.json +-------------------------------------------------------------------------------- + +The MIT License (MIT) +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +The MIT License (MIT) +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2015 present Alipay.com, https://www.alipay.com/ + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://react-component.github.io/trigger +Package Download URL: https://registry.npmjs.org/@rc-component/trigger/-/trigger-3.10.1.tgz +Dependency Path: @rc-component/picker > @rc-component/trigger +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + +-------------------------------------------------------------------------------- +Package Title: @rc-component/util (1.12.0) + +Package Locator: npm+@rc-component/util$1.12.0 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Shared React utilities for rc-component packages. + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE + - Copyright (c) 2014 present yiminghe + - Copyright (c) 2015 present Alipay.com, https://www.alipay.com/ +- package.json +-------------------------------------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +The MIT License (MIT) + +Copyright (c) 2014-present yiminghe +Copyright (c) 2015-present Alipay.com, https://www.alipay.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2014 present yiminghe +- Copyright (c) 2015 present Alipay.com, https://www.alipay.com/ + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://react-component.github.io/util +Package Download URL: https://registry.npmjs.org/@rc-component/util/-/util-1.12.0.tgz +Dependency Path: @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > @rc-component/util > @rc-component/picker > @rc-component/overflow > @rc-component/util > @rc-component/picker > @rc-component/resize-observer > @rc-component/util > @rc-component/picker > @rc-component/trigger > @rc-component/motion > @rc-component/util > @rc-component/picker > @rc-component/trigger > @rc-component/portal > @rc-component/util > @rc-component/picker > @rc-component/trigger > @rc-component/resize-observer > @rc-component/util > @rc-component/picker > @rc-component/trigger > @rc-component/util > @rc-component/picker > @rc-component/util +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: @react-dnd/invariant (4.0.2) @@ -32874,6 +33322,79 @@ Package Download URL: https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz Dependency Path: inquirer > cli-width File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml +-------------------------------------------------------------------------------- +Package Title: clsx (2.1.1) + +Package Locator: npm+clsx$2.1.1 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +A tiny (239B) utility for constructing className strings conditionally. + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- license + - Copyright (c) Luke Edwards (lukeed.com) +- package.json +-------------------------------------------------------------------------------- + +MIT License +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* License Header * +Copyright (c) Luke Edwards (lukeed.com) +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* Copyrights * +MIT +- Copyright (c) Luke Edwards (lukeed.com) + +* Package Info * + +Authors: luke@lukeed.com +Package Manager: NPM +Project URL: https://github.com/lukeed/clsx#readme +Package Download URL: https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz +Dependency Path: @rc-component/picker > @rc-component/overflow > clsx > @rc-component/picker > @rc-component/trigger > @rc-component/motion > clsx > @rc-component/picker > @rc-component/trigger > @rc-component/portal > clsx > @rc-component/picker > @rc-component/trigger > clsx > @rc-component/picker > clsx > @react-aria/interactions > react-aria > clsx +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: code-block-writer (13.0.3) @@ -47349,7 +47870,7 @@ Authors: opensource+npm@fb.com, react-core@meta.com Package Manager: NPM Project URL: https://react.dev/ Package Download URL: https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz -Dependency Path: @aaronhayes/react-use-hubspot-form > react-dom > scheduler > @floating-ui/react > @floating-ui/react-dom > react-dom > scheduler > @floating-ui/react > react-dom > scheduler > @floating-ui/react-dom > react-dom > scheduler > @react-aria/interactions > react-aria > react-dom > scheduler > @react-aria/interactions > react-dom > scheduler > @tanstack/react-virtual > react-dom > scheduler > ag-grid-react > react-dom > scheduler > react-dom > scheduler > react-lines-ellipsis > react-dom > scheduler +Dependency Path: @aaronhayes/react-use-hubspot-form > react-dom > scheduler > @floating-ui/react > @floating-ui/react-dom > react-dom > scheduler > @floating-ui/react > react-dom > scheduler > @floating-ui/react-dom > react-dom > scheduler > @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > react-dom > scheduler > @rc-component/picker > @rc-component/overflow > react-dom > scheduler > @rc-component/picker > @rc-component/trigger > @rc-component/motion > react-dom > scheduler > @rc-component/picker > @rc-component/trigger > @rc-component/portal > react-dom > scheduler > @rc-component/picker > react-dom > scheduler > react-dom > scheduler File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- @@ -55349,9 +55870,96 @@ SOFTWARE. * License Header * -The MIT License (MIT) +The MIT License (MIT) + +Copyright (c) Denis Malinochkin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) Denis Malinochkin + +* Package Info * + +Authors: dmalinochkin@rambler.ru +Package Manager: NPM +Project URL: https://www.npmjs.com/package/@nodelib/fs.scandir +Package Download URL: https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz +Dependency Path: @formatjs/cli-lib > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint > globby > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint-config-recommended > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint-config-recommended > stylelint > globby > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-order > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-plugin-defensive-css > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-scss > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + +-------------------------------------------------------------------------------- +Package Title: @peculiar/x509 (1.14.3) + +Package Locator: npm+@peculiar/x509$1.14.3 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +@peculiar/x509 is an easy to use TypeScript/Javascript library based on @peculiar/asn1-schema that makes generating X.509 Certificates and Certificate Requests as well as validating certificate chains easy + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- build/index.d.ts + - Copyright (c) Peculiar Ventures. All rights reserved. +- build/x509.cjs.js + - Copyright (c) Peculiar Ventures. All rights reserved. +- build/x509.es.js + - Copyright (c) Peculiar Ventures. All rights reserved. +- build/x509.js + - Copyright (c) Peculiar Ventures. All rights reserved. +- LICENSE + - Copyright (c) Peculiar Ventures. All rights reserved. +- package.json +-------------------------------------------------------------------------------- + +MIT License + +Copyright (c) Peculiar Ventures. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* License Header * +MIT License -Copyright (c) Denis Malinochkin +Copyright (c) Peculiar Ventures. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -55374,47 +55982,94 @@ SOFTWARE. * Copyrights * MIT -- Copyright (c) Denis Malinochkin +- Copyright (c) Peculiar Ventures. All rights reserved. * Package Info * -Authors: dmalinochkin@rambler.ru +Authors: apilguk@gmail.com, donskovdmitriyv@gmail.com, info@peculiarventures.com, microshine@mail.ru, mihailzachepilo@gmail.com, ryan_hurst@hotmail.com, yury@strozhevsky.com Package Manager: NPM -Project URL: https://www.npmjs.com/package/@nodelib/fs.scandir -Package Download URL: https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz -Dependency Path: @formatjs/cli-lib > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint > globby > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint-config-recommended > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-config-standard > stylelint-config-recommended > stylelint > globby > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-order > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-plugin-defensive-css > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir > stylelint-scss > stylelint > fast-glob > @nodelib/fs.walk > @nodelib/fs.scandir +Project URL: https://github.com/PeculiarVentures/x509#readme +Package Download URL: https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz +Dependency Path: webpack-dev-server > selfsigned > @peculiar/x509 File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- -Package Title: @peculiar/x509 (1.14.3) +Package Title: @rc-component/motion (1.3.3) -Package Locator: npm+@peculiar/x509$1.14.3 +Package Locator: npm+@rc-component/motion$1.3.3 Package Depth: Transitive -------------------------------------------------------------------------------- -@peculiar/x509 is an easy to use TypeScript/Javascript library based on @peculiar/asn1-schema that makes generating X.509 Certificates and Certificate Requests as well as validating certificate chains easy +React lifecycle controlled motion library + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- LICENSE.md + - Copyright (c) 2019 present afc163 +- package.json +-------------------------------------------------------------------------------- + +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* License Header * +The MIT License (MIT) + +Copyright (c) 2019-present afc163 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) 2019 present afc163 + +* Package Info * + +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com +Package Manager: NPM +Project URL: https://react-component.github.io/motion +Package Download URL: https://registry.npmjs.org/@rc-component/motion/-/motion-1.3.3.tgz +Dependency Path: @rc-component/picker > @rc-component/trigger > @rc-component/motion +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + +-------------------------------------------------------------------------------- +Package Title: @rc-component/portal (2.2.1) + +Package Locator: npm+@rc-component/portal$2.2.1 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +React Portal Component * Declared Licenses * MIT -------------------------------------------------------------------------------- File matches: -- build/index.d.ts - - Copyright (c) Peculiar Ventures. All rights reserved. -- build/x509.cjs.js - - Copyright (c) Peculiar Ventures. All rights reserved. -- build/x509.es.js - - Copyright (c) Peculiar Ventures. All rights reserved. -- build/x509.js - - Copyright (c) Peculiar Ventures. All rights reserved. - LICENSE - - Copyright (c) Peculiar Ventures. All rights reserved. + - Copyright (c) 2019 present react-component - package.json -------------------------------------------------------------------------------- MIT License -Copyright (c) Peculiar Ventures. All rights reserved. +Copyright (c) 2019-present react-component Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -55434,11 +56089,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * License Header * MIT License -Copyright (c) Peculiar Ventures. All rights reserved. +Copyright (c) 2019-present react-component Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -55458,18 +56112,17 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * Copyrights * MIT -- Copyright (c) Peculiar Ventures. All rights reserved. +- Copyright (c) 2019 present react-component * Package Info * -Authors: apilguk@gmail.com, donskovdmitriyv@gmail.com, info@peculiarventures.com, microshine@mail.ru, mihailzachepilo@gmail.com, ryan_hurst@hotmail.com, yury@strozhevsky.com +Authors: 1075746765@qq.com, afc163@gmail.com, scdzwyxst@gmail.com, smith3816@gmail.com, wasd2144@hotmail.com Package Manager: NPM -Project URL: https://github.com/PeculiarVentures/x509#readme -Package Download URL: https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz -Dependency Path: webpack-dev-server > selfsigned > @peculiar/x509 +Project URL: https://github.com/react-component/portal +Package Download URL: https://registry.npmjs.org/@rc-component/portal/-/portal-2.2.1.tgz +Dependency Path: @rc-component/picker > @rc-component/trigger > @rc-component/portal File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- @@ -61167,79 +61820,6 @@ Package Download URL: https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.t Dependency Path: webpack-cli > webpack-merge > clone-deep File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml --------------------------------------------------------------------------------- -Package Title: clsx (2.1.1) - -Package Locator: npm+clsx$2.1.1 - -Package Depth: Transitive --------------------------------------------------------------------------------- - -A tiny (239B) utility for constructing className strings conditionally. - -* Declared Licenses * -MIT --------------------------------------------------------------------------------- -File matches: -- license - - Copyright (c) Luke Edwards (lukeed.com) -- package.json --------------------------------------------------------------------------------- - -MIT License -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -* License Header * -Copyright (c) Luke Edwards (lukeed.com) -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -* Copyrights * -MIT -- Copyright (c) Luke Edwards (lukeed.com) - -* Package Info * - -Authors: luke@lukeed.com -Package Manager: NPM -Project URL: https://github.com/lukeed/clsx#readme -Package Download URL: https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz -Dependency Path: @react-aria/interactions > react-aria > clsx -File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml - -------------------------------------------------------------------------------- Package Title: combined-stream (1.0.8) @@ -66486,6 +67066,79 @@ Package Download URL: https://registry.npmjs.org/is-inside-container/-/is-inside Dependency Path: webpack-dev-server > open > is-inside-container > webpack-dev-server > open > wsl-utils > is-wsl > is-inside-container File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml +-------------------------------------------------------------------------------- +Package Title: is-mobile (5.0.0) + +Package Locator: npm+is-mobile$5.0.0 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Check if mobile browser. + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- package.json +- README.md + - Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> +-------------------------------------------------------------------------------- + +MIT License +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* License Header * +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* Copyrights * +MIT +- Copyright (c) 2013 Julian Gruber <julian@juliangruber.com> + +* Package Info * + +Authors: julian@juliangruber.com +Package Manager: NPM +Project URL: https://github.com/juliangruber/is-mobile +Package Download URL: https://registry.npmjs.org/is-mobile/-/is-mobile-5.0.0.tgz +Dependency Path: @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/overflow > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/resize-observer > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/trigger > @rc-component/motion > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/trigger > @rc-component/portal > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/trigger > @rc-component/resize-observer > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/trigger > @rc-component/util > is-mobile > @rc-component/picker > @rc-component/util > is-mobile +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: is-network-error (1.3.2) @@ -73341,6 +73994,88 @@ Package Download URL: https://registry.npmjs.org/range-parser/-/range-parser-1.3 Dependency Path: webpack-dev-server > webpack-dev-middleware > range-parser File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml +-------------------------------------------------------------------------------- +Package Title: react-is (19.2.8) + +Package Locator: npm+react-is$19.2.8 + +Package Depth: Transitive +-------------------------------------------------------------------------------- + +Brand checking of React Elements. + +* Declared Licenses * +MIT +-------------------------------------------------------------------------------- +File matches: +- cjs/react-is.development.js + - Copyright (c) Meta Platforms, Inc. and affiliates. +- cjs/react-is.production.js + - Copyright (c) Meta Platforms, Inc. and affiliates. +- LICENSE + - Copyright (c) Meta Platforms, Inc. and affiliates. +- package.json +-------------------------------------------------------------------------------- + +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* License Header * +MIT License + +Copyright (c) Meta Platforms, Inc. and affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +* Copyrights * +MIT +- Copyright (c) Meta Platforms, Inc. and affiliates. + +* Package Info * + +Authors: opensource+npm@fb.com, react-core@meta.com +Package Manager: NPM +Project URL: https://react.dev/ +Dependency Path: @rc-component/picker > @rc-component/overflow > @rc-component/resize-observer > @rc-component/util > react-is > @rc-component/picker > @rc-component/overflow > @rc-component/util > react-is > @rc-component/picker > @rc-component/resize-observer > @rc-component/util > react-is > @rc-component/picker > @rc-component/trigger > @rc-component/motion > @rc-component/util > react-is > @rc-component/picker > @rc-component/trigger > @rc-component/portal > @rc-component/util > react-is > @rc-component/picker > @rc-component/trigger > @rc-component/resize-observer > @rc-component/util > react-is > @rc-component/picker > @rc-component/trigger > @rc-component/util > react-is > @rc-component/picker > @rc-component/util > react-is +File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml + -------------------------------------------------------------------------------- Package Title: react-stately (3.48.0) @@ -100056,9 +100791,9 @@ MIT * Package Info * -Authors: brian.woodward@gmail.com, github@sellside.com, trysound@yandex.ru +Authors: brian.woodward@gmail.com, github@sellside.com, opensource@trysound.io Package Manager: NPM -Project URL: https://www.npmjs.com/package/isobject +Project URL: https://github.com/jonschlinkert/isobject Package Download URL: https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz Dependency Path: webpack-cli > webpack-merge > clone-deep > is-plain-object > isobject File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml @@ -104997,4 +105732,4 @@ File Path(s): common/config/subspaces/sdk/pnpm-lock.yaml -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -Report Generated by FOSSA on 2026-8-24 \ No newline at end of file +Report Generated by FOSSA on 2026-8-26 \ No newline at end of file diff --git a/common/changes/@gooddata/sdk-ui-all/GDP-3376-absolute-date-filter-granularities-step-2_2026-07-27-13-10.json b/common/changes/@gooddata/sdk-ui-all/GDP-3376-absolute-date-filter-granularities-step-2_2026-07-27-13-10.json new file mode 100644 index 00000000000..18633c66243 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/GDP-3376-absolute-date-filter-granularities-step-2_2026-07-27-13-10.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-filters: Add the new PeriodRangePicker date picker component (with a Storybook story per granularity), along with the supporting static date filter granularity types and period-boundary conversion utilities (not yet wired into DateFilter)", + "type": "patch", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/JSVA-F1-2810-filter-view-parameter-reset_2026-08-25-09-14-00.json b/common/changes/@gooddata/sdk-ui-all/JSVA-F1-2810-filter-view-parameter-reset_2026-08-25-09-14-00.json new file mode 100644 index 00000000000..a8c92405769 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/JSVA-F1-2810-filter-view-parameter-reset_2026-08-25-09-14-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-ui-dashboard: Reset parameters omitted by an applied filter view instead of keeping the previously applied value", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/LX-2865-feature-flag_2026-08-24-00-00.json b/common/changes/@gooddata/sdk-ui-all/LX-2865-feature-flag_2026-08-24-00-00.json new file mode 100644 index 00000000000..a42071b5228 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/LX-2865-feature-flag_2026-08-24-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "sdk-model: Add the enableBusinessBriefingReportsApp feature flag", + "type": "patch", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/dsom-f1-2563-inherit-csv-delimiter-automations_2026-08-17.json b/common/changes/@gooddata/sdk-ui-all/dsom-f1-2563-inherit-csv-delimiter-automations_2026-08-17.json new file mode 100644 index 00000000000..2ba03c27d11 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/dsom-f1-2563-inherit-csv-delimiter-automations_2026-08-17.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui: Added an `Inherit` option to the CSV delimiter picker used in scheduled exports, alerts, and ad-hoc CSV exports. When selected (the new default when no delimiter is saved), no delimiter is sent and the workspace/organization default applies.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/ine-cq-2800_2026-08-20-13-00-00.json b/common/changes/@gooddata/sdk-ui-all/ine-cq-2800_2026-08-20-13-00-00.json new file mode 100644 index 00000000000..c5311db18ce --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/ine-cq-2800_2026-08-20-13-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "analytics-as-code: Support computed attributes as code - new computed_attribute YAML type with its JSON schema, TS and Python types, YAML/declarative converters both ways, deploy and clone wiring, MAQL reference resolution, snippet and init rules", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/ine-cq-2852_2026-08-24-13-30-00.json b/common/changes/@gooddata/sdk-ui-all/ine-cq-2852_2026-08-24-13-30-00.json new file mode 100644 index 00000000000..bda2af7c2bf --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/ine-cq-2852_2026-08-24-13-30-00.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-all: Add support for computed attributes in model and AD.", + "type": "minor" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "ivan.nejezchleb@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-actionbar-slot_2026-08-24.json b/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-actionbar-slot_2026-08-24.json new file mode 100644 index 00000000000..2c313f361eb --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-actionbar-slot_2026-08-24.json @@ -0,0 +1,15 @@ +{ + "changes": [ + { + "comment": "sdk-ui-kit: ConfirmDialogBase accepts a footerRenderer prop replacing the whole footer; the default footer is extracted into ConfirmDialogFooter (internal)", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + }, + { + "comment": "sdk-ui-dashboard: Added an ActionBar slot and topContent/bottomContent props to the default alerting and scheduled email dialogs (alpha)", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-islotprops-relocation_2026-08-25.json b/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-islotprops-relocation_2026-08-25.json new file mode 100644 index 00000000000..7b0bc9fdf11 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/jnk-gdp-3167-islotprops-relocation_2026-08-25.json @@ -0,0 +1,15 @@ +{ + "changes": [ + { + "comment": "sdk-ui-kit: Added the ISlotProps slot contract (alpha), moved from sdk-ui-dashboard", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + }, + { + "comment": "sdk-ui-dashboard: ISlotProps is now re-exported from sdk-ui-kit; the sdk-ui-dashboard export is unchanged for consumers", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/lx-2811_2026-08-24-10-00-00.json b/common/changes/@gooddata/sdk-ui-all/lx-2811_2026-08-24-10-00-00.json new file mode 100644 index 00000000000..31051f6e62e --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/lx-2811_2026-08-24-10-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Apply the workspace number separators to visualizations embedded in the AI chat, so they match the same insight in Analyze", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/mnaj-claude-ci-worker-result-stl-2575-pin-cron-parser_2026-08-25-21-35.json b/common/changes/@gooddata/sdk-ui-all/mnaj-claude-ci-worker-result-stl-2575-pin-cron-parser_2026-08-25-21-35.json new file mode 100644 index 00000000000..514bd81d86d --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/mnaj-claude-ci-worker-result-stl-2575-pin-cron-parser_2026-08-25-21-35.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-kit, sdk-ui-ext: Pin the cron-parser dependency to the exact version 5.9.0 instead of the ^5.1.1 range.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/nce-f1-2789-mekko-zoom_2026-08-25-10-46.json b/common/changes/@gooddata/sdk-ui-all/nce-f1-2789-mekko-zoom_2026-08-25-10-46.json new file mode 100644 index 00000000000..38ce8fe8015 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/nce-f1-2789-mekko-zoom_2026-08-25-10-46.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "sdk-ui-ext: add zoom and pan support to Mekko chart", + "type": "none", + "packageName": "@gooddata/sdk-ui-all" + } + ], + "packageName": "@gooddata/sdk-ui-all", + "email": "nikola.cech@gooddata.com" +} diff --git a/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-08-20-13-00-00.json b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-08-20-13-00-00.json new file mode 100644 index 00000000000..bf24e384a6d --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/pvep-master_2026-08-20-13-00-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: A new AI assistant conversation starts in the Quick reasoning mode instead of Thinking.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/changes/@gooddata/sdk-ui-all/sha_master_1_2026-08-25-14-05-00.json b/common/changes/@gooddata/sdk-ui-all/sha_master_1_2026-08-25-14-05-00.json new file mode 100644 index 00000000000..07d14a6f850 --- /dev/null +++ b/common/changes/@gooddata/sdk-ui-all/sha_master_1_2026-08-25-14-05-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@gooddata/sdk-ui-all", + "comment": "sdk-ui-gen-ai: Enhance reference handling and update UI for tooltips over them.", + "type": "none" + } + ], + "packageName": "@gooddata/sdk-ui-all" +} diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 4a3fd4bea35..5cd4dd37526 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -2529,6 +2529,9 @@ importers: exponential-backoff: specifier: ^3.1.1 version: 3.1.3 + fast-json-patch: + specifier: ^3.1.1 + version: 3.1.1 lodash-es: specifier: ^4.17.23 version: 4.18.1 @@ -4336,8 +4339,8 @@ importers: specifier: 2.5.1 version: 2.5.1 cron-parser: - specifier: ^5.1.1 - version: 5.6.2 + specifier: 5.9.0 + version: 5.9.0 date-fns: specifier: 4.1.0 version: 4.1.0 @@ -4564,6 +4567,9 @@ importers: '@gooddata/util': specifier: workspace:* version: link:../util + '@rc-component/picker': + specifier: 1.12.0 + version: 1.12.0(date-fns@4.1.0)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@reduxjs/toolkit': specifier: 2.9.0 version: 2.9.0(react-redux@9.2.0(@types/react@19.1.11)(react@19.1.1)(redux@5.0.1))(react@19.1.1) @@ -5255,8 +5261,8 @@ importers: specifier: ^3.3.3 version: 3.3.3 cron-parser: - specifier: ^5.1.1 - version: 5.6.2 + specifier: 5.9.0 + version: 5.9.0 date-fns: specifier: 4.1.0 version: 4.1.0 @@ -11432,6 +11438,64 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@rc-component/motion@1.3.3': + resolution: {integrity: sha512-Xh3IszxvlSv3/PLYFyC2UZi9LNB83yOnkB/LNmRzaypZLvkhqUIPS7MQpGZcCMWrNsXV2p6YTSWbSGvFpEle9A==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/overflow@1.0.1': + resolution: {integrity: sha512-syfmgAABaHCnCDzPwHZ/2tuvIcpOO3jefYZMmfkN+pmo8HKTzsfhS57vxo4ksPdN0By+uWVJhJWNFozNBxi2eA==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/picker@1.12.0': + resolution: {integrity: sha512-0FZGgDiDZFMm2hcfGv4jyjm7yWIj2MiwfeTzLL0vWkO+8cCSKdiM9XhWpkn1aAsoI2EwUy48Oz2cGfvL8ZKrfw==} + engines: {node: '>=12.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + + '@rc-component/portal@2.2.1': + resolution: {integrity: sha512-ck+r1kW/JSv0wxPji3KN2ss9K6Z0qqwusw/mf/0JobXhZ8hC2ejZwCJObW/SvDi0uhA0VzmCnx0CaCci95tcmA==} + engines: {node: '>=12.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/resize-observer@1.1.2': + resolution: {integrity: sha512-t/Bb0W8uvL4PYKAB3YcChC+DlHh0Wt5kM7q/J+0qpVEUMLe7Hk5zuvc9km0hMnTFPSx5Z7Wu/fzCLN6erVLE8Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/trigger@3.10.1': + resolution: {integrity: sha512-mXlDN0IXdtV8Yqqm8195ECCyrbmfvvfKvwVvSlH0+qvKD6BUF8gRhEjSy0FOcD1+CcDRHgTiX99LoxfQrmh3Cw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/util@1.12.0': + resolution: {integrity: sha512-AEjPL8JVdohIITaiXokyjL9WQ6tKWWjAYK9QU16tGNE9JaQABBQy+hA4H2Lup5MgXy9yY3iLrbZJheuU13hTdQ==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + '@react-aria/interactions@3.28.1': resolution: {integrity: sha512-Bqb+HrD5I5MHS2SKBhISYqo2SW8Y2dfzgF/Y1lIJq7xqLxheo9vzxPGEHhz+XzkgGfoqEJx8A6a3C7uiqS3HWA==} peerDependencies: @@ -13350,10 +13414,9 @@ packages: engines: {node: '>=12.0.0'} deprecated: v4 is no longer maintained, upgrade to v5 - cron-parser@5.6.2: - resolution: {integrity: sha512-yJ/G1LVir6CnlkLI40CsampPLKl1SprGGlUagWtGJxewytRVYezv5xVyzzbT+Pvzx+VIRvZVF7/a0eEMTxdnTA==} + cron-parser@5.9.0: + resolution: {integrity: sha512-W42Tm/zNt2Z3HTXDoev3nrx+SF3eCaD1rFecnHx0zgwrzhO9I6EcKeB35XaV4FDX64wBXWFbhYLTPvQpvpR1lA==} engines: {node: '>=18'} - deprecated: 'Published tarball was built from a stale dist/ and is missing the fixes from #414 and #415 — its contents are effectively v5.6.1. Upgrade to v5.7.0.' cross-spawn@6.0.6: resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} @@ -14073,6 +14136,9 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} + fast-json-patch@3.1.1: + resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -14852,6 +14918,9 @@ packages: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} + is-mobile@5.0.0: + resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -16338,6 +16407,9 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-is@19.2.8: + resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==} + react-lines-ellipsis@0.16.1: resolution: {integrity: sha512-cQefaTdPlmvOAoQlcBOuv3AG2csThsdzCWSGydUZhv6VrrIsLShJ+WmxnCEHa3jAQeH4lxlsNVBd6i4bE5h2+g==} peerDependencies: @@ -20356,6 +20428,66 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@rc-component/motion@1.3.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 2.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@rc-component/overflow@1.0.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@babel/runtime': 7.29.7 + '@rc-component/resize-observer': 1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 2.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@rc-component/picker@1.12.0(date-fns@4.1.0)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@rc-component/overflow': 1.0.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/resize-observer': 1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/trigger': 3.10.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 2.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + date-fns: 4.1.0 + luxon: 3.7.2 + moment: 2.30.1 + + '@rc-component/portal@2.2.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 2.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@rc-component/resize-observer@1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@rc-component/trigger@3.10.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@rc-component/motion': 1.3.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/portal': 2.2.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/resize-observer': 1.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@rc-component/util': 1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + clsx: 2.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@rc-component/util@1.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + is-mobile: 5.0.0 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-is: 19.2.8 + '@react-aria/interactions@3.28.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@react-types/shared': 3.36.0(react@19.1.1) @@ -22314,7 +22446,7 @@ snapshots: dependencies: luxon: 3.7.2 - cron-parser@5.6.2: + cron-parser@5.9.0: dependencies: luxon: 3.7.2 @@ -23234,6 +23366,8 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-json-patch@3.1.1: {} + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -24046,6 +24180,8 @@ snapshots: is-map@2.0.3: {} + is-mobile@5.0.0: {} + is-negative-zero@2.0.3: {} is-network-error@1.3.2: {} @@ -25810,6 +25946,8 @@ snapshots: react-is@18.3.1: {} + react-is@19.2.8: {} + react-lines-ellipsis@0.16.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: react: 19.1.1 diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 093169410f0..a07bb99e12c 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -2,14 +2,14 @@ { "definitionName": "lockStepVersion", "policyName": "sdk", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" }, { "definitionName": "lockStepVersion", "policyName": "sdk-not-npm-publish", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "nextBump": "prerelease", "mainProject": "@gooddata/sdk-ui-all" } diff --git a/examples/playground/package.json b/examples/playground/package.json index f6bcbe5a8e6..f970c912caa 100644 --- a/examples/playground/package.json +++ b/examples/playground/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/playground", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": true, "description": "GoodData.UI SDK - Developer Playground", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples-template/package.json b/examples/sdk-interactive-examples/examples-template/package.json index db290e29553..ea412e767c4 100644 --- a/examples/sdk-interactive-examples/examples-template/package.json +++ b/examples/sdk-interactive-examples/examples-template/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-examples-template", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "GoodData interactive example template", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-attributefilter/package.json b/examples/sdk-interactive-examples/examples/example-attributefilter/package.json index b510a249d39..0a0d20328c1 100644 --- a/examples/sdk-interactive-examples/examples/example-attributefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-attributefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-attributefilter", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example demonstrates how to use the AttributeFilter component to filter data in a visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-chartconfig/package.json b/examples/sdk-interactive-examples/examples/example-chartconfig/package.json index 1c699c4e706..bc1e31d1123 100644 --- a/examples/sdk-interactive-examples/examples/example-chartconfig/package.json +++ b/examples/sdk-interactive-examples/examples/example-chartconfig/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-chartconfig", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This interactive example demonstrates how to manipulate the chart config.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-columnchart/package.json b/examples/sdk-interactive-examples/examples/example-columnchart/package.json index 3757c1bf811..858f612fe06 100644 --- a/examples/sdk-interactive-examples/examples/example-columnchart/package.json +++ b/examples/sdk-interactive-examples/examples/example-columnchart/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-columnchart", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example demonstrates the usage of the ColumnChart component with the viewBy and stackBy properties.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-combochart/package.json b/examples/sdk-interactive-examples/examples/example-combochart/package.json index 88ecfd90830..a0d027012bb 100644 --- a/examples/sdk-interactive-examples/examples/example-combochart/package.json +++ b/examples/sdk-interactive-examples/examples/example-combochart/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-combochart", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "Example demonstrates ComboChart secondaryMeasures definition. ", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-dashboard/package.json b/examples/sdk-interactive-examples/examples/example-dashboard/package.json index b2ef64c4267..48aeb1c52c2 100644 --- a/examples/sdk-interactive-examples/examples/example-dashboard/package.json +++ b/examples/sdk-interactive-examples/examples/example-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-dashboard", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example shows how to use the Dashboard component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-datefilter/package.json b/examples/sdk-interactive-examples/examples/example-datefilter/package.json index 063b059b66b..999b56c3672 100644 --- a/examples/sdk-interactive-examples/examples/example-datefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-datefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-datefilter", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "Example demonstrates usage of Date Filter component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json b/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json index f1defa10a07..c2989e4ad71 100644 --- a/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json +++ b/examples/sdk-interactive-examples/examples/example-dependentfilters/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-dependentfilters", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example demonstrates how to use multiple attribute filters linked together to filter data in a visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-execute/package.json b/examples/sdk-interactive-examples/examples/example-execute/package.json index fde9d6ec032..8b7c9cb1a71 100644 --- a/examples/sdk-interactive-examples/examples/example-execute/package.json +++ b/examples/sdk-interactive-examples/examples/example-execute/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-execute", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example demonstrates using Execute component and build custom visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-granularity/package.json b/examples/sdk-interactive-examples/examples/example-granularity/package.json index cc1632b2ede..c3fb227bab7 100644 --- a/examples/sdk-interactive-examples/examples/example-granularity/package.json +++ b/examples/sdk-interactive-examples/examples/example-granularity/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-granularity", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example exmplains DateFilter granularity ", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-headline/package.json b/examples/sdk-interactive-examples/examples/example-headline/package.json index 4fa3bbcafb7..690f8499f2e 100644 --- a/examples/sdk-interactive-examples/examples/example-headline/package.json +++ b/examples/sdk-interactive-examples/examples/example-headline/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-headline", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example shows how to use the Headline component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-pivottable/package.json b/examples/sdk-interactive-examples/examples/example-pivottable/package.json index 453fa331415..8820f1c5ba8 100644 --- a/examples/sdk-interactive-examples/examples/example-pivottable/package.json +++ b/examples/sdk-interactive-examples/examples/example-pivottable/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-pivottable", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "Basic PivotTable manipulation.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json b/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json index 86923ef8dbd..44b8186803f 100644 --- a/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json +++ b/examples/sdk-interactive-examples/examples/example-relativedatefilter/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-relativedatefilter", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "Example demonstrates how to set relative DateFilter for visualization.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/examples/example-repeater/package.json b/examples/sdk-interactive-examples/examples/example-repeater/package.json index e043d456f38..7a84e4a5849 100644 --- a/examples/sdk-interactive-examples/examples/example-repeater/package.json +++ b/examples/sdk-interactive-examples/examples/example-repeater/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-example-repeater", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "This example demonstrates how to use Repeater component.", "license": "LicenseRef-LICENSE", diff --git a/examples/sdk-interactive-examples/package.json b/examples/sdk-interactive-examples/package.json index 1ec1c03c0e7..ad144d93fde 100644 --- a/examples/sdk-interactive-examples/package.json +++ b/examples/sdk-interactive-examples/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-interactive-examples", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "private": false, "description": "GoodData React interactive examples", "license": "LicenseRef-LICENSE", diff --git a/libs/api-client-tiger/api/api-client-tiger.api.md b/libs/api-client-tiger/api/api-client-tiger.api.md index 9c3f82b5580..ce93a4f3747 100644 --- a/libs/api-client-tiger/api/api-client-tiger.api.md +++ b/libs/api-client-tiger/api/api-client-tiger.api.md @@ -2144,7 +2144,7 @@ export interface AfmModelObjectIdentifierCoreIdentifier { } // @public (undocumented) -export type AfmModelObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AfmModelObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; // @public export interface AfmModelObjectIdentifierDataset { @@ -2172,7 +2172,7 @@ export interface AfmModelObjectIdentifierIdentifier { } // @public (undocumented) -export type AfmModelObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AfmModelObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; // @public (undocumented) export interface AfmModelObjectIdentifierLabel { @@ -2189,7 +2189,7 @@ export interface AfmModelObjectIdentifierLabelIdentifier { } // @public (undocumented) -export type AfmModelObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AfmModelObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; // @public export interface AfmNegativeAttributeFilter { @@ -2248,7 +2248,7 @@ export interface AfmObjectIdentifierCoreIdentifier { } // @public (undocumented) -export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; // @public export interface AfmObjectIdentifierDataset { @@ -2276,7 +2276,7 @@ export interface AfmObjectIdentifierIdentifier { } // @public (undocumented) -export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; // @public (undocumented) export interface AfmObjectIdentifierLabel { @@ -2293,7 +2293,7 @@ export interface AfmObjectIdentifierLabelIdentifier { } // @public (undocumented) -export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; // @public export interface AfmObjectIdentifierParameter { @@ -11129,7 +11129,7 @@ export interface AutomationAfmObjectIdentifierCoreIdentifier { } // @public (undocumented) -export type AutomationAfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AutomationAfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; // @public export interface AutomationAfmObjectIdentifierDataset { @@ -11157,7 +11157,7 @@ export interface AutomationAfmObjectIdentifierIdentifier { } // @public (undocumented) -export type AutomationAfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AutomationAfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; // @public (undocumented) export interface AutomationAfmObjectIdentifierLabel { @@ -11174,7 +11174,7 @@ export interface AutomationAfmObjectIdentifierLabelIdentifier { } // @public (undocumented) -export type AutomationAfmObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AutomationAfmObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; // @public export interface AutomationAfmObjectIdentifierParameter { @@ -39870,7 +39870,7 @@ export type MetadataGetEntitiesOptions = { export type MetadataGetEntitiesParams = MetadataGetEntitiesWorkspaceParams | MetadataGetEntitiesUserParams | MetadataGetEntitiesThemeParams | MetadataGetEntitiesColorPaletteParams; // @internal -export type MetadataGetEntitiesResult = JsonApiVisualizationObjectOutList | JsonApiAnalyticalDashboardOutList | JsonApiDashboardPluginOutList | JsonApiDatasetOutList | JsonApiAttributeOutList | JsonApiLabelOutList | JsonApiMetricOutList | JsonApiFactOutList | JsonApiFilterContextOutList | JsonApiApiTokenOutList | JsonApiThemeOutList | JsonApiColorPaletteOutList | JsonApiWorkspaceThemeOutList | JsonApiWorkspaceColorPaletteOutList | JsonApiExportDefinitionOutList | JsonApiAutomationOutList | JsonApiUserOutList | JsonApiNotificationChannelOutList | JsonApiNotificationChannelIdentifierOutList; +export type MetadataGetEntitiesResult = JsonApiVisualizationObjectOutList | JsonApiAnalyticalDashboardOutList | JsonApiDashboardPluginOutList | JsonApiDatasetOutList | JsonApiAttributeOutList | JsonApiComputedAttributeOutList | JsonApiLabelOutList | JsonApiMetricOutList | JsonApiFactOutList | JsonApiFilterContextOutList | JsonApiApiTokenOutList | JsonApiThemeOutList | JsonApiColorPaletteOutList | JsonApiWorkspaceThemeOutList | JsonApiWorkspaceColorPaletteOutList | JsonApiExportDefinitionOutList | JsonApiAutomationOutList | JsonApiUserOutList | JsonApiNotificationChannelOutList | JsonApiNotificationChannelIdentifierOutList; // @internal export type MetadataGetEntitiesThemeParams = { diff --git a/libs/api-client-tiger/package.json b/libs/api-client-tiger/package.json index d422b4aba85..1aa5063187d 100644 --- a/libs/api-client-tiger/package.json +++ b/libs/api-client-tiger/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/api-client-tiger", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "API Client for GoodData Cloud and GoodData.CN", "license": "MIT", "author": "GoodData", diff --git a/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts b/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts index fb72bb56bc2..04028eca2d1 100644 --- a/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts +++ b/libs/api-client-tiger/src/endpoints/entitiesObjects/index.ts @@ -92,6 +92,21 @@ export { type EntitiesApiUpdateEntityMetricsRequest, type EntitiesApiPatchEntityMetricsRequest, type EntitiesApiDeleteEntityMetricsRequest, + // EntitiesApi - ComputedAttributes + EntitiesApi_GetAllEntitiesComputedAttributes, + EntitiesApi_GetEntityComputedAttributes, + EntitiesApi_CreateEntityComputedAttributes, + EntitiesApi_UpdateEntityComputedAttributes, + EntitiesApi_PatchEntityComputedAttributes, + EntitiesApi_DeleteEntityComputedAttributes, + EntitiesApi_SearchEntitiesComputedAttributes, + type EntitiesApiGetAllEntitiesComputedAttributesRequest, + type EntitiesApiGetEntityComputedAttributesRequest, + type EntitiesApiCreateEntityComputedAttributesRequest, + type EntitiesApiUpdateEntityComputedAttributesRequest, + type EntitiesApiPatchEntityComputedAttributesRequest, + type EntitiesApiDeleteEntityComputedAttributesRequest, + type EntitiesApiSearchEntitiesComputedAttributesRequest, // EntitiesApi - Facts EntitiesApi_GetAllEntitiesFacts, EntitiesApi_GetEntityFacts, diff --git a/libs/api-client-tiger/src/generated/afm-rest-api/api.ts b/libs/api-client-tiger/src/generated/afm-rest-api/api.ts index 72df77088dd..8fde382539d 100644 --- a/libs/api-client-tiger/src/generated/afm-rest-api/api.ts +++ b/libs/api-client-tiger/src/generated/afm-rest-api/api.ts @@ -213,7 +213,7 @@ export interface AfmObjectIdentifierCoreIdentifier { 'type': AfmObjectIdentifierCoreIdentifierTypeEnum; } -export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; /** * Reference to the date dataset to which the filter should be applied. @@ -234,7 +234,7 @@ export interface AfmObjectIdentifierIdentifier { 'type': AfmObjectIdentifierIdentifierTypeEnum; } -export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; export interface AfmObjectIdentifierLabel { 'identifier': AfmObjectIdentifierLabelIdentifier; @@ -245,7 +245,7 @@ export interface AfmObjectIdentifierLabelIdentifier { 'type': AfmObjectIdentifierLabelIdentifierTypeEnum; } -export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; /** * Reference to the parameter. diff --git a/libs/api-client-tiger/src/generated/afm-rest-api/openapi-spec.json b/libs/api-client-tiger/src/generated/afm-rest-api/openapi-spec.json index 46ff865cea7..7898cd2e54c 100644 --- a/libs/api-client-tiger/src/generated/afm-rest-api/openapi-spec.json +++ b/libs/api-client-tiger/src/generated/afm-rest-api/openapi-spec.json @@ -4093,6 +4093,7 @@ "enum": [ "analyticalDashboard", "attribute", + "computedAttribute", "dashboardPlugin", "dataset", "fact", @@ -4161,7 +4162,8 @@ "attribute", "label", "fact", - "metric" + "metric", + "computedAttribute" ] } } @@ -4219,7 +4221,8 @@ "type": { "type": "string", "enum": [ - "label" + "label", + "computedAttribute" ] } } diff --git a/libs/api-client-tiger/src/generated/automation-json-api/api.ts b/libs/api-client-tiger/src/generated/automation-json-api/api.ts index 46183ac0c4f..ec72693a3d1 100644 --- a/libs/api-client-tiger/src/generated/automation-json-api/api.ts +++ b/libs/api-client-tiger/src/generated/automation-json-api/api.ts @@ -179,7 +179,7 @@ export interface AutomationAfmObjectIdentifierCoreIdentifier { 'type': AutomationAfmObjectIdentifierCoreIdentifierTypeEnum; } -export type AutomationAfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AutomationAfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; /** * Date dataset used for anomaly detection. @@ -200,7 +200,7 @@ export interface AutomationAfmObjectIdentifierIdentifier { 'type': AutomationAfmObjectIdentifierIdentifierTypeEnum; } -export type AutomationAfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AutomationAfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; export interface AutomationAfmObjectIdentifierLabel { 'identifier': AutomationAfmObjectIdentifierLabelIdentifier; @@ -211,7 +211,7 @@ export interface AutomationAfmObjectIdentifierLabelIdentifier { 'type': AutomationAfmObjectIdentifierLabelIdentifierTypeEnum; } -export type AutomationAfmObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AutomationAfmObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; /** * Reference to the parameter. diff --git a/libs/api-client-tiger/src/generated/automation-json-api/openapi-spec.json b/libs/api-client-tiger/src/generated/automation-json-api/openapi-spec.json index f04549f0e84..85da7add8f8 100644 --- a/libs/api-client-tiger/src/generated/automation-json-api/openapi-spec.json +++ b/libs/api-client-tiger/src/generated/automation-json-api/openapi-spec.json @@ -709,6 +709,7 @@ "enum": [ "analyticalDashboard", "attribute", + "computedAttribute", "dashboardPlugin", "dataset", "fact", @@ -777,7 +778,8 @@ "attribute", "label", "fact", - "metric" + "metric", + "computedAttribute" ] } } @@ -835,7 +837,8 @@ "type": { "type": "string", "enum": [ - "label" + "label", + "computedAttribute" ] } } diff --git a/libs/api-client-tiger/src/generated/metadata-json-api/api.ts b/libs/api-client-tiger/src/generated/metadata-json-api/api.ts index 25362657fd4..4157bbc51c7 100644 --- a/libs/api-client-tiger/src/generated/metadata-json-api/api.ts +++ b/libs/api-client-tiger/src/generated/metadata-json-api/api.ts @@ -151,7 +151,7 @@ export interface AfmObjectIdentifierCoreIdentifier { 'type': AfmObjectIdentifierCoreIdentifierTypeEnum; } -export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric'; +export type AfmObjectIdentifierCoreIdentifierTypeEnum = 'attribute' | 'label' | 'fact' | 'metric' | 'computedAttribute'; /** * Reference to the date dataset to which the filter should be applied. @@ -172,7 +172,7 @@ export interface AfmObjectIdentifierIdentifier { 'type': AfmObjectIdentifierIdentifierTypeEnum; } -export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; +export type AfmObjectIdentifierIdentifierTypeEnum = 'analyticalDashboard' | 'attribute' | 'computedAttribute' | 'dashboardPlugin' | 'dataset' | 'fact' | 'label' | 'metric' | 'prompt' | 'visualizationObject' | 'filterContext'; export interface AfmObjectIdentifierLabel { 'identifier': AfmObjectIdentifierLabelIdentifier; @@ -183,7 +183,7 @@ export interface AfmObjectIdentifierLabelIdentifier { 'type': AfmObjectIdentifierLabelIdentifierTypeEnum; } -export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label'; +export type AfmObjectIdentifierLabelIdentifierTypeEnum = 'label' | 'computedAttribute'; /** * Reference to the parameter. diff --git a/libs/api-client-tiger/src/generated/metadata-json-api/openapi-spec.json b/libs/api-client-tiger/src/generated/metadata-json-api/openapi-spec.json index c35d73efd4c..8fdfc5ed679 100644 --- a/libs/api-client-tiger/src/generated/metadata-json-api/openapi-spec.json +++ b/libs/api-client-tiger/src/generated/metadata-json-api/openapi-spec.json @@ -28108,6 +28108,7 @@ "enum": [ "analyticalDashboard", "attribute", + "computedAttribute", "dashboardPlugin", "dataset", "fact", @@ -28176,7 +28177,8 @@ "attribute", "label", "fact", - "metric" + "metric", + "computedAttribute" ] } } @@ -28234,7 +28236,8 @@ "type": { "type": "string", "enum": [ - "label" + "label", + "computedAttribute" ] } } diff --git a/libs/api-client-tiger/src/metadataUtilities.ts b/libs/api-client-tiger/src/metadataUtilities.ts index 4d1ecee1be7..1a82bc76e91 100644 --- a/libs/api-client-tiger/src/metadataUtilities.ts +++ b/libs/api-client-tiger/src/metadataUtilities.ts @@ -10,6 +10,7 @@ import { type JsonApiAttributeOutList, type JsonApiAutomationOutList, type JsonApiColorPaletteOutList, + type JsonApiComputedAttributeOutList, type JsonApiDashboardPluginOutList, type JsonApiDatasetOutList, type JsonApiExportDefinitionOutList, @@ -117,6 +118,7 @@ export type MetadataGetEntitiesResult = | JsonApiDashboardPluginOutList | JsonApiDatasetOutList | JsonApiAttributeOutList + | JsonApiComputedAttributeOutList | JsonApiLabelOutList | JsonApiMetricOutList | JsonApiFactOutList diff --git a/libs/sdk-backend-base/api/sdk-backend-base.api.md b/libs/sdk-backend-base/api/sdk-backend-base.api.md index 514145962b0..29b140930ba 100644 --- a/libs/sdk-backend-base/api/sdk-backend-base.api.md +++ b/libs/sdk-backend-base/api/sdk-backend-base.api.md @@ -37,6 +37,7 @@ import { IAuthenticationProvider } from '@gooddata/sdk-backend-spi'; import { IBucket } from '@gooddata/sdk-model'; import { ICatalogAttribute } from '@gooddata/sdk-model'; import { ICatalogAttributeHierarchy } from '@gooddata/sdk-model'; +import { ICatalogComputedAttribute } from '@gooddata/sdk-model'; import { ICatalogDateAttribute } from '@gooddata/sdk-model'; import { ICatalogDateDataset } from '@gooddata/sdk-model'; import { ICatalogFact } from '@gooddata/sdk-model'; @@ -52,6 +53,7 @@ import { IChatThreadQuery } from '@gooddata/sdk-backend-spi'; import { IClusteringConfig } from '@gooddata/sdk-backend-spi'; import { IClusteringResult } from '@gooddata/sdk-backend-spi'; import { ICollectionItemsConfig } from '@gooddata/sdk-backend-spi'; +import { IComputedAttributeMetadataObject } from '@gooddata/sdk-model'; import { IDashboard } from '@gooddata/sdk-model'; import { IDashboardAttributeFilterConfig } from '@gooddata/sdk-model'; import { IDashboardBase } from '@gooddata/sdk-model'; @@ -380,6 +382,16 @@ export class CatalogAttributeBuilder extends GroupableCatalogItemBuilder { + // (undocumented) + computedAttribute(computedAttribute: IComputedAttributeMetadataObject): this; + // (undocumented) + defaultDisplayForm(displayForm: IAttributeDisplayFormMetadataObject): this; + // (undocumented) + displayForms(displayForms: IAttributeDisplayFormMetadataObject[]): this; +} + // @beta export class CatalogDateAttributeBuilder extends Builder { // (undocumented) @@ -620,6 +632,8 @@ export abstract class DecoratedWorkspaceCatalog implements IWorkspaceCatalog { // (undocumented) availableItems(): IWorkspaceCatalogAvailableItemsFactory; // (undocumented) + computedAttributes(): ICatalogComputedAttribute[]; + // (undocumented) dateDatasets(): ICatalogDateDataset[]; // (undocumented) facts(): ICatalogFact[]; @@ -1309,6 +1323,9 @@ export const newAttributeMetadataObject: (ref: ObjRef, modifications?: BuilderMo // @beta export const newCatalogAttribute: (modifications?: BuilderModifications>) => ICatalogAttribute; +// @beta +export const newCatalogComputedAttribute: (modifications: BuilderModifications>) => ICatalogComputedAttribute; + // @beta export const newCatalogDateAttribute: (modifications?: BuilderModifications>) => ICatalogDateAttribute; diff --git a/libs/sdk-backend-base/package.json b/libs/sdk-backend-base/package.json index fc90f25006d..c1c4dc972e0 100644 --- a/libs/sdk-backend-base/package.json +++ b/libs/sdk-backend-base/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-base", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData.UI SDK - Base for backend implementations", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.fixtures.ts b/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.helpers.ts similarity index 100% rename from libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.fixtures.ts rename to libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.helpers.ts diff --git a/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.ts b/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.ts index 8c289c8cddb..22480171e9c 100644 --- a/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.ts +++ b/libs/sdk-backend-base/src/convertors/fromBackend/AfmResultConverter.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { type IResultHeader, isResultAttributeHeader } from "@gooddata/sdk-model"; import { transformResultHeaders } from "./afm/result.js"; -import { resultHeaders, transformedResultHeaders } from "./AfmResultConverter.fixtures.js"; +import { resultHeaders, transformedResultHeaders } from "./AfmResultConverter.test.helpers.js"; const transformResultHeader = (resultHeader: IResultHeader): IResultHeader => { if (!isResultAttributeHeader(resultHeader)) { diff --git a/libs/sdk-backend-base/src/customBackend/workspace.ts b/libs/sdk-backend-base/src/customBackend/workspace.ts index ac96480c8a3..4d4ad44db3f 100644 --- a/libs/sdk-backend-base/src/customBackend/workspace.ts +++ b/libs/sdk-backend-base/src/customBackend/workspace.ts @@ -13,6 +13,7 @@ import { type IWorkspaceAttributesService, type IWorkspaceAutomationService, type IWorkspaceCatalogFactory, + type IWorkspaceComputedAttributesService, type IWorkspaceDashboardsService, type IWorkspaceDatasetsService, type IWorkspaceDescriptor, @@ -104,6 +105,10 @@ export class CustomWorkspace implements IAnalyticalWorkspace { throw new NotSupported("parameters service is not supported"); } + public computedAttributes(): IWorkspaceComputedAttributesService { + throw new NotSupported("computed attributes service is not supported"); + } + public facts(): IWorkspaceFactsService { throw new NotSupported("measures service is not supported"); } diff --git a/libs/sdk-backend-base/src/decoratedBackend/analyticalWorkspace.ts b/libs/sdk-backend-base/src/decoratedBackend/analyticalWorkspace.ts index 6eff08f9199..2f6c7e6071d 100644 --- a/libs/sdk-backend-base/src/decoratedBackend/analyticalWorkspace.ts +++ b/libs/sdk-backend-base/src/decoratedBackend/analyticalWorkspace.ts @@ -13,6 +13,7 @@ import { type IWorkspaceAttributesService, type IWorkspaceAutomationService, type IWorkspaceCatalogFactory, + type IWorkspaceComputedAttributesService, type IWorkspaceDashboardsService, type IWorkspaceDatasetsService, type IWorkspaceDescriptor, @@ -106,6 +107,10 @@ export class AnalyticalWorkspaceDecorator implements IAnalyticalWorkspace { return this.decorated.parameters(); } + public computedAttributes(): IWorkspaceComputedAttributesService { + return this.decorated.computedAttributes(); + } + public facts(): IWorkspaceFactsService { const { facts } = this.factories; diff --git a/libs/sdk-backend-base/src/decoratedBackend/catalog.ts b/libs/sdk-backend-base/src/decoratedBackend/catalog.ts index fc46fe67784..71fa9fdf76b 100644 --- a/libs/sdk-backend-base/src/decoratedBackend/catalog.ts +++ b/libs/sdk-backend-base/src/decoratedBackend/catalog.ts @@ -1,4 +1,4 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation import { type IWorkspaceCatalog, @@ -11,6 +11,7 @@ import { type CatalogItemType, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, @@ -119,4 +120,8 @@ export abstract class DecoratedWorkspaceCatalog implements IWorkspaceCatalog { public attributeHierarchies(): ICatalogAttributeHierarchy[] { return this.decorated.attributeHierarchies(); } + + public computedAttributes(): ICatalogComputedAttribute[] { + return this.decorated.computedAttributes(); + } } diff --git a/libs/sdk-backend-base/src/dummyBackend/index.ts b/libs/sdk-backend-base/src/dummyBackend/index.ts index d07c9eb0e41..e524fa696c2 100644 --- a/libs/sdk-backend-base/src/dummyBackend/index.ts +++ b/libs/sdk-backend-base/src/dummyBackend/index.ts @@ -116,6 +116,7 @@ import { type IWorkspaceCatalogFactoryOptions, type IWorkspaceCatalogWithAvailableItems, type IWorkspaceCatalogWithAvailableItemsFactoryOptions, + type IWorkspaceComputedAttributesService, type IWorkspaceDashboardsService, type IWorkspaceDatasetsService, type IWorkspaceDescriptor, @@ -160,6 +161,7 @@ import { type IBucket, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, @@ -480,6 +482,9 @@ function dummyWorkspace(workspace: string, config: DummyBackendConfig): IAnalyti parameters(): IWorkspaceParametersService { return new DummyWorkspaceParametersService(workspace); }, + computedAttributes(): IWorkspaceComputedAttributesService { + throw new NotSupported("not supported"); + }, facts(): IWorkspaceFactsService { return new DummyWorkspaceFactsService(workspace); }, @@ -831,6 +836,10 @@ class DummyWorkspaceCatalog implements IWorkspaceCatalog { public attributeHierarchies(): ICatalogAttributeHierarchy[] { return []; } + + public computedAttributes(): ICatalogComputedAttribute[] { + return []; + } } class DummyWorkspaceCatalogAvailableItemsFactory implements IWorkspaceCatalogAvailableItemsFactory { @@ -968,6 +977,14 @@ class DummyWorkspaceCatalogWithAvailableItems implements IWorkspaceCatalogWithAv public availableAttributeHierarchies(): ICatalogAttributeHierarchy[] { return []; } + + public computedAttributes(): ICatalogComputedAttribute[] { + return []; + } + + public availableComputedAttributes(): ICatalogComputedAttribute[] { + return []; + } } class DummyLlmProvidersQuery implements ILlmProvidersQuery { diff --git a/libs/sdk-backend-base/src/index.ts b/libs/sdk-backend-base/src/index.ts index adba4346d66..c5f313a8c8a 100644 --- a/libs/sdk-backend-base/src/index.ts +++ b/libs/sdk-backend-base/src/index.ts @@ -162,6 +162,10 @@ export { } from "./ldmFactories/dashboard/kpiWidgetFactory.js"; export { type IWidgetBaseBuilder, WidgetBaseBuilder } from "./ldmFactories/dashboard/widgetFactory.js"; export { CatalogAttributeBuilder, newCatalogAttribute } from "./ldmFactories/catalog/attributeFactory.js"; +export { + CatalogComputedAttributeBuilder, + newCatalogComputedAttribute, +} from "./ldmFactories/catalog/computedAttributeFactory.js"; export { CatalogDateAttributeBuilder, CatalogDateDatasetBuilder, diff --git a/libs/sdk-backend-base/src/ldmFactories/catalog/computedAttributeFactory.ts b/libs/sdk-backend-base/src/ldmFactories/catalog/computedAttributeFactory.ts new file mode 100644 index 00000000000..39c112f959d --- /dev/null +++ b/libs/sdk-backend-base/src/ldmFactories/catalog/computedAttributeFactory.ts @@ -0,0 +1,48 @@ +// (C) 2026 GoodData Corporation + +import { + type IAttributeDisplayFormMetadataObject, + type ICatalogComputedAttribute, + type IComputedAttributeMetadataObject, +} from "@gooddata/sdk-model"; + +import { type BuilderModifications, builderFactory } from "../builder.js"; + +import { GroupableCatalogItemBuilder } from "./groupFactory.js"; + +/** + * Catalog computed attribute builder + * See {@link Builder} + * + * @beta + */ +export class CatalogComputedAttributeBuilder< + T extends ICatalogComputedAttribute = ICatalogComputedAttribute, +> extends GroupableCatalogItemBuilder { + public computedAttribute(computedAttribute: IComputedAttributeMetadataObject): this { + this.item.computedAttribute = computedAttribute; + return this; + } + + public defaultDisplayForm(displayForm: IAttributeDisplayFormMetadataObject): this { + this.item.defaultDisplayForm = displayForm; + return this; + } + + public displayForms(displayForms: IAttributeDisplayFormMetadataObject[]): this { + this.item.displayForms = displayForms; + return this; + } +} + +/** + * Catalog computed attribute factory + * + * @param modifications - catalog computed attribute builder modifications to perform + * @returns created catalog computed attribute + * @beta + */ +export const newCatalogComputedAttribute = ( + modifications: BuilderModifications, +): ICatalogComputedAttribute => + builderFactory(CatalogComputedAttributeBuilder, { type: "computedAttribute" }, modifications); diff --git a/libs/sdk-backend-mockingbird/api/sdk-backend-mockingbird.api.md b/libs/sdk-backend-mockingbird/api/sdk-backend-mockingbird.api.md index 1447f8491ff..7bc851020d0 100644 --- a/libs/sdk-backend-mockingbird/api/sdk-backend-mockingbird.api.md +++ b/libs/sdk-backend-mockingbird/api/sdk-backend-mockingbird.api.md @@ -18,6 +18,7 @@ import { IAvailableAccessGrantee } from '@gooddata/sdk-model'; import { IBackendCapabilities } from '@gooddata/sdk-backend-spi'; import { ICatalogAttribute } from '@gooddata/sdk-model'; import { ICatalogAttributeHierarchy } from '@gooddata/sdk-model'; +import { ICatalogComputedAttribute } from '@gooddata/sdk-model'; import { ICatalogDateDataset } from '@gooddata/sdk-model'; import { ICatalogFact } from '@gooddata/sdk-model'; import { ICatalogGroup } from '@gooddata/sdk-model'; @@ -174,6 +175,7 @@ export type RecordedBackendConfig = IAnalyticalBackendConfig & { availableFacts?: (facts: ICatalogFact[]) => ICatalogFact[]; availableDateDatasets?: (datasets: ICatalogDateDataset[]) => ICatalogDateDataset[]; availableAttributeHierarchies?: (attributeHierarchies: ICatalogAttributeHierarchy[]) => ICatalogAttributeHierarchy[]; + availableComputedAttributes?: (computedAttributes: ICatalogComputedAttribute[]) => ICatalogComputedAttribute[]; }; userManagement?: IUserManagement; attributeElementsFiltering?: AttributeElementsFiltering; diff --git a/libs/sdk-backend-mockingbird/package.json b/libs/sdk-backend-mockingbird/package.json index 8c3fc77d7be..ccce91adf62 100644 --- a/libs/sdk-backend-mockingbird/package.json +++ b/libs/sdk-backend-mockingbird/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-mockingbird", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "Mock GoodData Backend SPI implementation", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts index f39984b9cc2..9400129c669 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/catalog.ts @@ -15,6 +15,7 @@ import { type IAttributeOrMeasure, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, @@ -23,6 +24,7 @@ import { type ObjRef, isCatalogAttribute, isCatalogAttributeHierarchy, + isCatalogComputedAttribute, isCatalogDateDataset, isCatalogFact, isCatalogMeasure, @@ -158,6 +160,10 @@ class RecordedCatalogBase { public attributeHierarchies(): ICatalogAttributeHierarchy[] { return this.items.filter(isCatalogAttributeHierarchy); } + + public computedAttributes(): ICatalogComputedAttribute[] { + return this.items.filter(isCatalogComputedAttribute); + } } class RecordedCatalog extends RecordedCatalogBase implements IWorkspaceCatalog { @@ -278,6 +284,7 @@ class RecordedAvailableCatalog extends RecordedCatalogBase implements IWorkspace private readonly filteredFacts: ICatalogFact[]; private readonly filteredDateDatasets: ICatalogDateDataset[]; private readonly filteredAttributeHierarchies: ICatalogAttributeHierarchy[]; + private readonly filteredComputedAttributes: ICatalogComputedAttribute[]; constructor( public readonly workspace: string, @@ -295,6 +302,7 @@ class RecordedAvailableCatalog extends RecordedCatalogBase implements IWorkspace availableFacts = typedIdentity, availableDateDatasets = typedIdentity, availableAttributeHierarchies = typedIdentity, + availableComputedAttributes = typedIdentity, } = this.config.catalogAvailability ?? {}; this.filteredAttributes = availableAttributes(this.attributes()); @@ -302,6 +310,7 @@ class RecordedAvailableCatalog extends RecordedCatalogBase implements IWorkspace this.filteredFacts = availableFacts(this.facts()); this.filteredDateDatasets = availableDateDatasets(this.dateDatasets()); this.filteredAttributeHierarchies = availableAttributeHierarchies(this.attributeHierarchies()); + this.filteredComputedAttributes = availableComputedAttributes(this.computedAttributes()); } public allAvailableItems = (): CatalogItem[] => { @@ -311,6 +320,7 @@ class RecordedAvailableCatalog extends RecordedCatalogBase implements IWorkspace ...this.filteredFacts, ...this.filteredDateDatasets, ...this.filteredAttributeHierarchies, + ...this.filteredComputedAttributes, ]; }; public availableAttributes = (): ICatalogAttribute[] => { @@ -328,4 +338,7 @@ class RecordedAvailableCatalog extends RecordedCatalogBase implements IWorkspace public availableAttributeHierarchies(): ICatalogAttributeHierarchy[] { return this.filteredAttributeHierarchies; } + public availableComputedAttributes(): ICatalogComputedAttribute[] { + return this.filteredComputedAttributes; + } } diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts index b47f8a459e0..64115d5ab77 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/index.ts @@ -44,6 +44,7 @@ import { type IWorkspaceAttributesService, type IWorkspaceAutomationService, type IWorkspaceCatalogFactory, + type IWorkspaceComputedAttributesService, type IWorkspaceDashboardsService, type IWorkspaceDatasetsService, type IWorkspaceDescriptor, @@ -243,6 +244,9 @@ function recordedWorkspace( parameters(): IWorkspaceParametersService { return new RecordedParameters(); }, + computedAttributes(): IWorkspaceComputedAttributesService { + throw new NotSupported("not supported"); + }, facts(): IWorkspaceFactsService { return new RecordedFacts(); }, diff --git a/libs/sdk-backend-mockingbird/src/recordedBackend/types.ts b/libs/sdk-backend-mockingbird/src/recordedBackend/types.ts index 5febbf6412f..1af27a90d11 100644 --- a/libs/sdk-backend-mockingbird/src/recordedBackend/types.ts +++ b/libs/sdk-backend-mockingbird/src/recordedBackend/types.ts @@ -17,6 +17,7 @@ import { type IAvailableAccessGrantee, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, @@ -123,6 +124,9 @@ export type RecordedBackendConfig = IAnalyticalBackendConfig & { availableAttributeHierarchies?: ( attributeHierarchies: ICatalogAttributeHierarchy[], ) => ICatalogAttributeHierarchy[]; + availableComputedAttributes?: ( + computedAttributes: ICatalogComputedAttribute[], + ) => ICatalogComputedAttribute[]; }; /** diff --git a/libs/sdk-backend-spi/api/sdk-backend-spi.api.md b/libs/sdk-backend-spi/api/sdk-backend-spi.api.md index e50840e281c..b2b422321b4 100644 --- a/libs/sdk-backend-spi/api/sdk-backend-spi.api.md +++ b/libs/sdk-backend-spi/api/sdk-backend-spi.api.md @@ -41,6 +41,7 @@ import { IAvailableAccessGrantee } from '@gooddata/sdk-model'; import { IBucket } from '@gooddata/sdk-model'; import { ICatalogAttribute } from '@gooddata/sdk-model'; import { ICatalogAttributeHierarchy } from '@gooddata/sdk-model'; +import { ICatalogComputedAttribute } from '@gooddata/sdk-model'; import { ICatalogDateDataset } from '@gooddata/sdk-model'; import { ICatalogFact } from '@gooddata/sdk-model'; import { ICatalogGroup } from '@gooddata/sdk-model'; @@ -48,6 +49,8 @@ import { ICatalogMeasure } from '@gooddata/sdk-model'; import { IColorPalette } from '@gooddata/sdk-model'; import { IColorPaletteDefinition } from '@gooddata/sdk-model'; import { IColorPaletteMetadataObject } from '@gooddata/sdk-model'; +import type { IComputedAttributeMetadataObject } from '@gooddata/sdk-model'; +import type { IComputedAttributeMetadataObjectDefinition } from '@gooddata/sdk-model'; import type { IDashboard } from '@gooddata/sdk-model'; import type { IDashboardAttributeFilterConfig } from '@gooddata/sdk-model'; import type { IDashboardBase } from '@gooddata/sdk-model'; @@ -375,6 +378,7 @@ export interface IAnalyticalWorkspace { // @alpha automations(): IWorkspaceAutomationService; catalog(): IWorkspaceCatalogFactory; + computedAttributes(): IWorkspaceComputedAttributesService; dashboards(): IWorkspaceDashboardsService; // @alpha dataFilters(): IDataFiltersService; @@ -762,9 +766,11 @@ export type IChatConversationCreateOptions = { // @internal export type IChatConversationDashboardContent = { type: "dashboard"; - dashboard: IDashboard | null; insights: IInsight[] | null; - saved: boolean; + dashboard?: IDashboard | null; + saved?: string | null; + base?: object | null; + patchError?: Error | null; }; // @internal @@ -936,7 +942,7 @@ export interface IChatConversationThread { // @internal export interface IChatConversationThreadQuery { - stream(): ReadableStream; + stream(history: IChatConversationItem[]): ReadableStream; withAllowedRelationshipTypes(relationshipTypes?: IAllowedRelationshipType[]): IChatConversationThreadQuery; withCreateLimit(createLimit: number): IChatConversationThreadQuery; withEffort(effort?: GenAIChatEffort): IChatConversationThreadQuery; @@ -1094,6 +1100,22 @@ export interface ICommentExpressionToken { value: string; } +// @public +export interface IComputedAttributesQuery { + query(): Promise; + withFilter(filter: IFilterBaseOptions): IComputedAttributesQuery; + withInclude(include: string[]): IComputedAttributesQuery; + // @beta + withMethod(method: QueryMethod): IComputedAttributesQuery; + withOrigin(origin: ObjectOrigin | (string & {})): IComputedAttributesQuery; + withPage(page: number): IComputedAttributesQuery; + withSize(size: number): IComputedAttributesQuery; + withSorting(sort: string[]): IComputedAttributesQuery; +} + +// @public +export type IComputedAttributesQueryResult = IPagedResource; + // @internal export interface ICreateKnowledgeDocumentRequest { // (undocumented) @@ -1756,6 +1778,11 @@ export interface IGetAutomationsQueryOptions { includeAutomationResult?: boolean; } +// @public +export interface IGetComputedAttributeOptions { + loadUserData?: boolean; +} + // @alpha export interface IGetDashboardOptions { exportId?: string; @@ -2854,6 +2881,7 @@ export interface IWorkspaceCatalogMethods { allItems(): CatalogItem[]; attributeHierarchies(): ICatalogAttributeHierarchy[]; attributes(): ICatalogAttribute[]; + computedAttributes(): ICatalogComputedAttribute[]; dateDatasets(): ICatalogDateDataset[]; facts(): ICatalogFact[]; groups(): ICatalogGroup[]; @@ -2865,6 +2893,7 @@ export interface IWorkspaceCatalogWithAvailableItems extends IWorkspaceCatalogMe allAvailableItems(): CatalogItem[]; availableAttributeHierarchies(): ICatalogAttributeHierarchy[]; availableAttributes(): ICatalogAttribute[]; + availableComputedAttributes(): ICatalogComputedAttribute[]; availableDateDatasets(): ICatalogDateDataset[]; availableFacts(): ICatalogFact[]; availableMeasures(): ICatalogMeasure[]; @@ -2876,6 +2905,17 @@ export interface IWorkspaceCatalogWithAvailableItemsFactoryOptions extends IWork items?: IAttributeOrMeasure[]; } +// @public +export interface IWorkspaceComputedAttributesService { + createComputedAttribute(computedAttribute: IComputedAttributeMetadataObjectDefinition): Promise; + deleteComputedAttribute(ref: ObjRef): Promise; + getComputedAttribute(ref: ObjRef, options?: IGetComputedAttributeOptions): Promise; + getComputedAttributeExpressionTokens(ref: ObjRef): Promise; + getComputedAttributesQuery(): IComputedAttributesQuery; + updateComputedAttribute(computedAttribute: IComputedAttributeMetadataObject): Promise; + updateComputedAttributeMeta(computedAttribute: Partial & IMetadataObjectIdentity): Promise; +} + // @alpha export interface IWorkspaceDashboardsService { createDashboard(dashboard: IDashboardDefinition): Promise; diff --git a/libs/sdk-backend-spi/package.json b/libs/sdk-backend-spi/package.json index 325a09e2afe..9ce69e70968 100644 --- a/libs/sdk-backend-spi/package.json +++ b/libs/sdk-backend-spi/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-spi", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData Backend SPI abstraction interfaces", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-backend-spi/src/index.ts b/libs/sdk-backend-spi/src/index.ts index 8e5cf0c8e61..959df011e6e 100644 --- a/libs/sdk-backend-spi/src/index.ts +++ b/libs/sdk-backend-spi/src/index.ts @@ -314,6 +314,13 @@ export type { export type { IWorkspaceFactsService, IFactsQuery, IFactsQueryResult } from "./workspace/facts/index.js"; +export type { + IWorkspaceComputedAttributesService, + IGetComputedAttributeOptions, + IComputedAttributesQuery, + IComputedAttributesQueryResult, +} from "./workspace/computedAttributes/index.js"; + export type { IWorkspaceDashboardsService, IGetDashboardOptions, diff --git a/libs/sdk-backend-spi/src/workspace/computedAttributes/index.ts b/libs/sdk-backend-spi/src/workspace/computedAttributes/index.ts new file mode 100644 index 00000000000..c630dca6a07 --- /dev/null +++ b/libs/sdk-backend-spi/src/workspace/computedAttributes/index.ts @@ -0,0 +1,186 @@ +// (C) 2026 GoodData Corporation + +import type { + IComputedAttributeMetadataObject, + IComputedAttributeMetadataObjectDefinition, + IMetadataObjectBase, + IMetadataObjectIdentity, + ObjRef, + ObjectOrigin, +} from "@gooddata/sdk-model"; + +import type { IFilterBaseOptions } from "../../common/filtering.js"; +import type { IPagedResource } from "../../common/paging.js"; +import type { QueryMethod } from "../../common/query.js"; +import type { IMeasureExpressionToken } from "../measures/measure.js"; + +/** + * Options for getting a computed attribute. + * + * @public + */ +export interface IGetComputedAttributeOptions { + /** + * Specifies whether information about the users who created or modified the computed attribute + * should be loaded. + * + * @remarks + * Defaults to false. + */ + loadUserData?: boolean; +} + +/** + * Service for create, update or delete computed attributes and querying them. + * + * @public + */ +export interface IWorkspaceComputedAttributesService { + /** + * Create and save computed attribute for the provided definition. + * + * @param computedAttribute - computed attribute definition + * @returns promise of created computed attribute + */ + createComputedAttribute( + computedAttribute: IComputedAttributeMetadataObjectDefinition, + ): Promise; + + /** + * Update provided computed attribute. + * + * @param computedAttribute - computed attribute to update + * @returns promise of updated computed attribute + */ + updateComputedAttribute( + computedAttribute: IComputedAttributeMetadataObject, + ): Promise; + + /** + * Update metadata of the computed attribute. + * + * @param computedAttribute - metadata update to apply + * @returns promise of updated computed attribute + */ + updateComputedAttributeMeta( + computedAttribute: Partial & IMetadataObjectIdentity, + ): Promise; + + /** + * Delete computed attribute with the given reference. + * + * @param ref - ref of the computed attribute to delete + * @returns promise of undefined + */ + deleteComputedAttribute(ref: ObjRef): Promise; + + /** + * Get computed attribute by reference. + * + * @param ref - ref of the computed attribute to get + * @param options - options for getting the computed attribute + * @returns promise of computed attribute + */ + getComputedAttribute( + ref: ObjRef, + options?: IGetComputedAttributeOptions, + ): Promise; + + /** + * Get the expression tokens of the computed attribute's MAQL, with every referenced object + * resolved to its title. + * + * @param ref - ref of the computed attribute + * @returns promise of the expression tokens + */ + getComputedAttributeExpressionTokens(ref: ObjRef): Promise; + + /** + * Computed attributes query factory. + * + * @returns computed attributes query + */ + getComputedAttributesQuery(): IComputedAttributesQuery; +} + +/** + * Service to query computed attributes. + * + * @public + */ +export interface IComputedAttributesQuery { + /** + * Sets number of computed attributes to return per page. + * Default size: 50 + * + * @param size - desired max number of computed attributes per page must be a positive number + * @returns computed attributes query + */ + withSize(size: number): IComputedAttributesQuery; + + /** + * Sets starting page for the query. Backend WILL return no data if the page is greater than + * total number of pages. + * Default page: 0 + * + * @param page - zero indexed, must be non-negative + * @returns computed attributes query + */ + withPage(page: number): IComputedAttributesQuery; + + /** + * Sets filter for the query. + * + * @param filter - filter to apply + * @returns computed attributes query + */ + withFilter(filter: IFilterBaseOptions): IComputedAttributesQuery; + + /** + * Sets sorting for the query. + * + * @param sort - Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported. + * @returns computed attributes query + */ + withSorting(sort: string[]): IComputedAttributesQuery; + + /** + * Sets include for the query. + * + * @param include - include to apply + * @returns computed attributes query + */ + withInclude(include: string[]): IComputedAttributesQuery; + + /** + * Sets origin for the query. + * + * @param origin - origin to apply. This is an open string union to allow platform-specific origin values in addition to the built-in literals. + * @returns computed attributes query + */ + withOrigin(origin: ObjectOrigin | (string & {})): IComputedAttributesQuery; + + /** + * Selects which backend endpoint flavor to use when listing computed attributes. + * Default method: "GET" + * + * @param method - endpoint flavor to use ("GET" or "POST") + * @returns computed attributes query + * @beta + */ + withMethod(method: QueryMethod): IComputedAttributesQuery; + + /** + * Starts the query. + * + * @returns promise of first page of the results + */ + query(): Promise; +} + +/** + * Queried computed attributes are returned in a paged representation. + * + * @public + */ +export type IComputedAttributesQueryResult = IPagedResource; diff --git a/libs/sdk-backend-spi/src/workspace/genAI/index.ts b/libs/sdk-backend-spi/src/workspace/genAI/index.ts index b1b53918d15..204ebbfafbc 100644 --- a/libs/sdk-backend-spi/src/workspace/genAI/index.ts +++ b/libs/sdk-backend-spi/src/workspace/genAI/index.ts @@ -1571,9 +1571,12 @@ export function isChatConversationSearchContent( */ export type IChatConversationDashboardContent = { type: "dashboard"; - dashboard: IDashboard | null; insights: IInsight[] | null; - saved: boolean; + dashboard?: IDashboard | null; + saved?: string | null; + //patch related + base?: object | null; + patchError?: Error | null; }; /** @@ -1693,7 +1696,7 @@ export interface IChatConversationThreadQuery { /** * Execute the chat thread and stream the results. */ - stream(): ReadableStream< - IChatConversationItem | IChatConversationError | IChatConversationInteractionStep - >; + stream( + history: IChatConversationItem[], + ): ReadableStream; } diff --git a/libs/sdk-backend-spi/src/workspace/index.ts b/libs/sdk-backend-spi/src/workspace/index.ts index 1b95f75d675..497b7018bc6 100644 --- a/libs/sdk-backend-spi/src/workspace/index.ts +++ b/libs/sdk-backend-spi/src/workspace/index.ts @@ -7,6 +7,7 @@ import { type IWorkspaceAgentsService } from "./agents/index.js"; import { type IAttributeHierarchiesService } from "./attributeHierarchies/index.js"; import { type IWorkspaceAttributesService } from "./attributes/index.js"; import { type IWorkspaceAutomationService } from "./automations/index.js"; +import { type IWorkspaceComputedAttributesService } from "./computedAttributes/index.js"; import { type IWorkspaceDashboardsService } from "./dashboards/index.js"; import { type IDataFiltersService } from "./dataFilter/index.js"; import { type IDateFilterConfigsQuery } from "./dateFilterConfigs/index.js"; @@ -115,6 +116,11 @@ export interface IAnalyticalWorkspace { */ facts(): IWorkspaceFactsService; + /** + * Returns service that can be used to manage and query computed attributes. + */ + computedAttributes(): IWorkspaceComputedAttributesService; + /** * Returns service that can be used to query data sets defined in this workspace. */ diff --git a/libs/sdk-backend-spi/src/workspace/ldm/catalog.ts b/libs/sdk-backend-spi/src/workspace/ldm/catalog.ts index 47eb14d21e3..c076b0f9277 100644 --- a/libs/sdk-backend-spi/src/workspace/ldm/catalog.ts +++ b/libs/sdk-backend-spi/src/workspace/ldm/catalog.ts @@ -1,10 +1,12 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { type CatalogItem, type CatalogItemType, type IAttributeOrMeasure, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, @@ -214,6 +216,13 @@ export interface IWorkspaceCatalogWithAvailableItems extends IWorkspaceCatalogMe * @returns array of available catalog attribute hierarchies */ availableAttributeHierarchies(): ICatalogAttributeHierarchy[]; + + /** + * Get all available catalog computed attributes + * + * @returns array of available catalog computed attributes + */ + availableComputedAttributes(): ICatalogComputedAttribute[]; } /** @@ -334,4 +343,11 @@ export interface IWorkspaceCatalogMethods { * @returns array of catalog attribute hierarchies */ attributeHierarchies(): ICatalogAttributeHierarchy[]; + + /** + * Get all catalog computed attributes + * + * @returns array of catalog computed attributes + */ + computedAttributes(): ICatalogComputedAttribute[]; } diff --git a/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md b/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md index 022b994882d..f54216390da 100644 --- a/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md +++ b/libs/sdk-backend-tiger/api/sdk-backend-tiger.api.md @@ -425,6 +425,7 @@ export const objectTypeToTigerIdType: { attributeHierarchy: TigerObjectType; automation: TigerObjectType; colorPalette: TigerObjectType; + computedAttribute: TigerObjectType; dashboardPlugin: TigerObjectType; dataSet: TigerObjectType; dateAttributeHierarchy: TigerObjectType; @@ -474,7 +475,7 @@ export type ScanSqlResult = ScanSqlResponse; export type SetJwtCallback = (jwt: string, secondsBeforeTokenExpirationToCallReminder?: number) => void; // @public -export type TigerAfmType = "label" | "metric" | "dataset" | "fact" | "attribute" | "prompt"; +export type TigerAfmType = "label" | "metric" | "dataset" | "fact" | "attribute" | "computedAttribute" | "prompt"; // @public export abstract class TigerAuthProviderBase implements IAuthenticationProvider { diff --git a/libs/sdk-backend-tiger/package.json b/libs/sdk-backend-tiger/package.json index 63cbfcb860e..d39f27fffa2 100644 --- a/libs/sdk-backend-tiger/package.json +++ b/libs/sdk-backend-tiger/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-backend-tiger", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN", "license": "MIT", "author": "GoodData", @@ -63,6 +63,7 @@ "date-fns-tz": "^3.2.0", "eventsource-parser": "~3.0.0", "exponential-backoff": "^3.1.1", + "fast-json-patch": "^3.1.1", "lodash-es": "^4.17.23", "lru-cache": "11.1.0", "spark-md5": "^3.0.0", diff --git a/libs/sdk-backend-tiger/scripts/refresh-md.sh b/libs/sdk-backend-tiger/scripts/refresh-md.sh index e1c49e2ad25..7bb4d2d4294 100755 --- a/libs/sdk-backend-tiger/scripts/refresh-md.sh +++ b/libs/sdk-backend-tiger/scripts/refresh-md.sh @@ -3,7 +3,7 @@ SCRIPTDIR=`dirname $0` ROOTDIR="${SCRIPTDIR}/.." EXPORTER="${ROOTDIR}/node_modules/.bin/gdc-catalog-export" -OUTPUT="${ROOTDIR}/src/fixtures/full.ts" +OUTPUT="${ROOTDIR}/tests/integrated/full.test.helpers.ts" PROJECTID="9c71fe9a4fc944d7b7886c4d05ce0cf3" $EXPORTER \ diff --git a/libs/sdk-backend-tiger/src/backend/features/feature.ts b/libs/sdk-backend-tiger/src/backend/features/feature.ts index cefc76dab79..206133c2920 100644 --- a/libs/sdk-backend-tiger/src/backend/features/feature.ts +++ b/libs/sdk-backend-tiger/src/backend/features/feature.ts @@ -906,6 +906,20 @@ export function mapFeatures(features: FeaturesMap): Partial "BOOLEAN", FeatureFlagsValues.enableAbsoluteDateFilterGranularity, ), + ...loadFeature( + features, + TigerFeaturesNames.EnableComputedAttributes, + "enableComputedAttributes", + "BOOLEAN", + FeatureFlagsValues.enableComputedAttributes, + ), + ...loadFeature( + features, + TigerFeaturesNames.EnableBusinessBriefingReportsApp, + "enableBusinessBriefingReportsApp", + "BOOLEAN", + FeatureFlagsValues.enableBusinessBriefingReportsApp, + ), }; } diff --git a/libs/sdk-backend-tiger/src/backend/uiFeatures.ts b/libs/sdk-backend-tiger/src/backend/uiFeatures.ts index 9aa16f786d5..abdb6ce52c6 100644 --- a/libs/sdk-backend-tiger/src/backend/uiFeatures.ts +++ b/libs/sdk-backend-tiger/src/backend/uiFeatures.ts @@ -135,6 +135,8 @@ export enum TigerFeaturesNames { EnableDashboardPersistentFiltersAcrossTabs = "enableDashboardPersistentFiltersAcrossTabs", EnableGenAiDashboardBuilderSkill = "enableGenAiDashboardBuilderSkill", EnableAbsoluteDateFilterGranularity = "enableAbsoluteDateFilterGranularity", + EnableComputedAttributes = "enableComputedAttributes", + EnableBusinessBriefingReportsApp = "enableBusinessBriefingReportsApp", } export type ITigerFeatureFlags = { @@ -265,6 +267,8 @@ export type ITigerFeatureFlags = { enableExportTimeoutFix: (typeof FeatureFlagsValues)["enableExportTimeoutFix"][number]; enableDashboardPersistentFiltersAcrossTabs: (typeof FeatureFlagsValues)["enableDashboardPersistentFiltersAcrossTabs"][number]; enableAbsoluteDateFilterGranularity: (typeof FeatureFlagsValues)["enableAbsoluteDateFilterGranularity"][number]; + enableComputedAttributes: (typeof FeatureFlagsValues)["enableComputedAttributes"][number]; + enableBusinessBriefingReportsApp: (typeof FeatureFlagsValues)["enableBusinessBriefingReportsApp"][number]; }; export const DefaultFeatureFlags: ITigerFeatureFlags = { @@ -395,6 +399,8 @@ export const DefaultFeatureFlags: ITigerFeatureFlags = { enableExportTimeoutFix: false, enableDashboardPersistentFiltersAcrossTabs: false, enableAbsoluteDateFilterGranularity: false, + enableComputedAttributes: false, + enableBusinessBriefingReportsApp: false, }; export const FeatureFlagsValues = { @@ -525,4 +531,6 @@ export const FeatureFlagsValues = { enableExportTimeoutFix: [true, false] as const, enableDashboardPersistentFiltersAcrossTabs: [true, false] as const, enableAbsoluteDateFilterGranularity: [true, false] as const, + enableComputedAttributes: [true, false] as const, + enableBusinessBriefingReportsApp: [false, true] as const, }; diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.test.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.test.ts index 62b9bfe30d4..938fd0b541d 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.test.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.test.ts @@ -18,7 +18,11 @@ import { newMeasure, } from "@gooddata/sdk-model"; -import { filterAvailableItems, sanitizeFiltersForValidObjects } from "./availableItemsFactory.js"; +import { + filterAvailableItems, + isComputedAttributeRef, + sanitizeFiltersForValidObjects, +} from "./availableItemsFactory.js"; describe("available item filtering", () => { describe("item filtering", () => { @@ -50,6 +54,70 @@ describe("available item filtering", () => { }); }); + describe("computed attributes", () => { + const displayForm = { + type: "displayForm" as const, + id: "rep_performance", + uri: "rep_performance", + ref: idRef("rep_performance", "computedAttribute"), + title: "Rep performance", + description: "", + production: true, + deprecated: false, + unlisted: false, + attribute: idRef("rep_performance", "computedAttribute"), + }; + const computedAttribute: CatalogItem = { + type: "computedAttribute", + groups: [], + computedAttribute: { + type: "computedAttribute", + ref: idRef("rep_performance", "computedAttribute"), + id: "rep_performance", + uri: "rep_performance", + title: "Rep performance", + description: "", + production: true, + deprecated: false, + unlisted: false, + expression: "SELECT 1", + displayForms: [displayForm], + }, + defaultDisplayForm: displayForm, + displayForms: [displayForm], + }; + + it("should recognise a computed attribute reference for the validObjects query", () => { + const ids = new Set(["rep_performance"]); + + // says what it is + expect(isComputedAttributeRef(idRef("rep_performance", "computedAttribute"), ids)).toBe(true); + // does NOT say what it is - an insight built before the reference carried the computed + // attribute type points at one as a plain label, and it must be dropped all the same + expect(isComputedAttributeRef(idRef("rep_performance", "displayForm"), ids)).toBe(true); + expect(isComputedAttributeRef(idRef("rep_performance"), ids)).toBe(true); + // a real attribute is untouched + expect(isComputedAttributeRef(idRef("region", "displayForm"), ids)).toBe(false); + }); + + it("should filter-in a computed attribute when its own ref matches", () => { + const result = filterAvailableItems( + [idRef("rep_performance", "computedAttribute")], + [computedAttribute], + ); + + expect(result).toEqual([computedAttribute]); + }); + + it("should filter-out a computed attribute the response does not mention", () => { + // the validObjects action cannot evaluate a computed attribute yet, so one never comes + // back in the response - which is why the factory passes them through separately + expect(filterAvailableItems([idRef("of_activities", "measure")], [computedAttribute])).toEqual( + [], + ); + }); + }); + describe("sanitizeFiltersForValidObjects", () => { const measureA = newMeasure("measure.a"); const measureB = newMeasure("measure.b"); diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.ts index e9654ca2e46..b7482a45e53 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/availableItemsFactory.ts @@ -27,9 +27,11 @@ import { isAttribute, isCatalogAttribute, isCatalogAttributeHierarchy, + isCatalogComputedAttribute, isCatalogFact, isCatalogMeasure, isFilter, + isIdentifierRef, isLocalIdRef, isMeasure, isMeasureValueFilter, @@ -86,7 +88,9 @@ const catalogItemRefs = (item: CatalogItem): ObjRef[] => { ? [item.measure.ref] : isCatalogAttributeHierarchy(item) ? [item.attributeHierarchy.ref] - : item.dateAttributes.map((attr) => attr.attribute.ref); + : isCatalogComputedAttribute(item) + ? [item.computedAttribute.ref] + : item.dateAttributes.map((attr) => attr.attribute.ref); }; export class TigerWorkspaceCatalogAvailableItemsFactory implements IWorkspaceCatalogAvailableItemsFactory { @@ -173,7 +177,23 @@ export class TigerWorkspaceCatalogAvailableItemsFactory implements IWorkspaceCat const relevantItems = insight ? [...insightMeasures(insight), ...insightAttributes(insight), ...insightFilters(insight)] : items; - const attributes = relevantItems.filter(isAttribute); + // The validObjects action does not accept a computed attribute yet, and one in the query + // makes it fail for the WHOLE insight - which takes the catalog availability and the date + // datasets down with it. Leaving computed attributes out narrows the answer (their own + // restrictions are not applied) instead of losing it. + // + // Identified against the CATALOG rather than against the reference's own type: an insight + // built before the reference carried the computed attribute type still points at one with a + // plain displayForm type, and such a reference must be dropped too or the request 400s. + // TODO INE (CQ-2796): include them once the action accepts them + const computedAttributeIds = new Set( + this.items.filter(isCatalogComputedAttribute).map((item) => item.computedAttribute.id), + ); + const attributes = relevantItems + .filter(isAttribute) + .filter( + (attribute) => !isComputedAttributeRef(attribute.attribute.displayForm, computedAttributeIds), + ); const measures = relevantItems.filter(isMeasure); const filters = relevantItems.filter(isFilter); @@ -207,9 +227,18 @@ export class TigerWorkspaceCatalogAvailableItemsFactory implements IWorkspaceCat const availableItems = afmValidObjectsQueryEmpty ? this.items : filterAvailableItems(availableObjRefs, this.items); - const allAvailableItems = types.includes("attributeHierarchy") - ? [...availableItems, ...this.items.filter(isCatalogAttributeHierarchy)] - : [...availableItems]; + const allAvailableItems = [ + ...availableItems, + ...(types.includes("attributeHierarchy") ? this.items.filter(isCatalogAttributeHierarchy) : []), + // The action cannot evaluate a computed attribute yet, so one would never come back in + // the response and filterAvailableItems would drop it - hence the pass-through. Only + // when the query was actually sent: an empty query already answers with every item, and + // appending would list the computed attributes twice. + // TODO INE (CQ-2796): drop this once the action evaluates them + ...(types.includes("computedAttribute") && !afmValidObjectsQueryEmpty + ? this.items.filter(isCatalogComputedAttribute) + : []), + ]; return new TigerWorkspaceCatalogWithAvailableItems( this.groups, @@ -220,6 +249,15 @@ export class TigerWorkspaceCatalogAvailableItemsFactory implements IWorkspaceCat } } +/** + * Whether a reference points at a computed attribute - either because it says so, or because its + * identifier is one of the workspace's computed attributes. The fabricated display form of a + * computed attribute shares the computed attribute's id, so the identifier match holds for both the + * attribute reference and its display form reference. + */ +export const isComputedAttributeRef = (ref: ObjRef, computedAttributeIds: Set) => + isIdentifierRef(ref) && (ref.type === "computedAttribute" || computedAttributeIds.has(ref.identifier)); + /** * @internal */ diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalog.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalog.ts index 16cd404bb46..99c5b8972ed 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalog.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalog.ts @@ -11,12 +11,14 @@ import { type CatalogItem, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, type ICatalogMeasure, isCatalogAttribute, isCatalogAttributeHierarchy, + isCatalogComputedAttribute, isCatalogDateDataset, isCatalogFact, isCatalogMeasure, @@ -64,6 +66,10 @@ export class TigerWorkspaceCatalog implements IWorkspaceCatalog { return this.items.filter(isCatalogAttributeHierarchy); } + public computedAttributes(): ICatalogComputedAttribute[] { + return this.items.filter(isCatalogComputedAttribute); + } + public availableItems(): IWorkspaceCatalogAvailableItemsFactory { return new TigerWorkspaceCatalogAvailableItemsFactory( this.authCall, diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalogWithAvailableItems.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalogWithAvailableItems.ts index 1b1a4a14911..f89dc5555cf 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalogWithAvailableItems.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/catalogWithAvailableItems.ts @@ -1,4 +1,5 @@ -// (C) 2019-2025 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + import { invariant } from "ts-invariant"; import { @@ -9,12 +10,14 @@ import { type CatalogItem, type ICatalogAttribute, type ICatalogAttributeHierarchy, + type ICatalogComputedAttribute, type ICatalogDateDataset, type ICatalogFact, type ICatalogGroup, type ICatalogMeasure, isCatalogAttribute, isCatalogAttributeHierarchy, + isCatalogComputedAttribute, isCatalogDateDataset, isCatalogFact, isCatalogMeasure, @@ -57,6 +60,10 @@ export class TigerWorkspaceCatalogWithAvailableItems implements IWorkspaceCatalo return this.items.filter(isCatalogAttributeHierarchy); } + public computedAttributes(): ICatalogComputedAttribute[] { + return this.items.filter(isCatalogComputedAttribute); + } + public allAvailableItems(): CatalogItem[] { return this.availableItems; } @@ -80,4 +87,8 @@ export class TigerWorkspaceCatalogWithAvailableItems implements IWorkspaceCatalo public availableAttributeHierarchies(): ICatalogAttributeHierarchy[] { return this.availableItems.filter(isCatalogAttributeHierarchy); } + + public availableComputedAttributes(): ICatalogComputedAttribute[] { + return this.availableItems.filter(isCatalogComputedAttribute); + } } diff --git a/libs/sdk-backend-tiger/src/backend/workspace/catalog/factory.ts b/libs/sdk-backend-tiger/src/backend/workspace/catalog/factory.ts index 02dc3feb547..24fa5386c86 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/catalog/factory.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/catalog/factory.ts @@ -4,6 +4,7 @@ import { sortBy, uniqBy } from "lodash-es"; import { MetadataUtilities, ValidateRelationsHeader } from "@gooddata/api-client-tiger"; import { + EntitiesApi_GetAllEntitiesComputedAttributes, EntitiesApi_GetAllEntitiesFacts, EntitiesApi_GetAllEntitiesMetrics, } from "@gooddata/api-client-tiger/endpoints/entitiesObjects"; @@ -15,6 +16,7 @@ import { import { type CatalogItem, type CatalogItemType, + type ICatalogComputedAttribute, type ICatalogFact, type ICatalogGroup, type ICatalogMeasure, @@ -22,11 +24,16 @@ import { type IdentifierRef, type ObjRef, isCatalogAttribute, + isCatalogComputedAttribute, isCatalogFact, isCatalogMeasure, } from "@gooddata/sdk-model"; -import { convertFact, convertMeasure } from "../../../convertors/fromBackend/CatalogConverter.js"; +import { + convertComputedAttributeToCatalogItem, + convertFact, + convertMeasure, +} from "../../../convertors/fromBackend/CatalogConverter.js"; import { type TigerAuthenticatedCallGuard } from "../../../types/index.js"; import { TigerWorkspaceCatalog } from "./catalog.js"; @@ -97,6 +104,9 @@ export class TigerWorkspaceCatalogFactory implements IWorkspaceCatalogFactory { if (this.options.types.includes("fact")) { promises.push(this.loadFacts()); } + if (this.options.types.includes("computedAttribute")) { + promises.push(this.loadComputedAttributes()); + } const includeAttributes = this.options.types.includes("attribute"); const includeDateDatasets = this.options.types.includes("dateDataset"); @@ -132,6 +142,9 @@ export class TigerWorkspaceCatalogFactory implements IWorkspaceCatalogFactory { if (isCatalogMeasure(item)) { return item.measure.title; } + if (isCatalogComputedAttribute(item)) { + return item.computedAttribute.title; + } return undefined; }; @@ -193,6 +206,30 @@ export class TigerWorkspaceCatalogFactory implements IWorkspaceCatalogFactory { return facts.data.map(convertFact); }; + private loadComputedAttributes = async (): Promise => { + const rsqlTagFilter = tagsToRsqlFilter(this.options); + const rsqlSearchFilter = searchToRsqlFilter(this.options); + const params = addRsqlFilterToParams( + { workspaceId: this.workspace }, + rsqlAnd(rsqlTagFilter, rsqlSearchFilter), + ); + + const computedAttributes = await this.authCall((client) => { + return MetadataUtilities.getAllPagesOf( + client, + EntitiesApi_GetAllEntitiesComputedAttributes, + params, + { + signal: this.signal, + }, + ).then(MetadataUtilities.mergeEntitiesResults); + }); + + return computedAttributes.data.map((computedAttribute) => + convertComputedAttributeToCatalogItem(computedAttribute, computedAttributes.included), + ); + }; + // Groups are collected from all catalog entities. // There is no separate endpoint for the tags anymore. private extractGroups(catalogItems: CatalogItem[]): ICatalogGroup[] { diff --git a/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/computedAttributesQuery.ts b/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/computedAttributesQuery.ts new file mode 100644 index 00000000000..d6d4cfff1a9 --- /dev/null +++ b/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/computedAttributesQuery.ts @@ -0,0 +1,138 @@ +// (C) 2026 GoodData Corporation + +import { + type EntitiesApiGetAllEntitiesComputedAttributesRequest, + MetadataUtilities, +} from "@gooddata/api-client-tiger"; +import { + EntitiesApi_GetAllEntitiesComputedAttributes, + EntitiesApi_SearchEntitiesComputedAttributes, +} from "@gooddata/api-client-tiger/endpoints/entitiesObjects"; +import { ServerPaging } from "@gooddata/sdk-backend-base"; +import { + type IComputedAttributesQuery, + type IComputedAttributesQueryResult, + type IFilterBaseOptions, + type QueryMethod, +} from "@gooddata/sdk-backend-spi"; +import type { ObjectOrigin } from "@gooddata/sdk-model"; + +import { convertComputedAttributesWithLinks } from "../../../convertors/fromBackend/ComputedAttributeConverter.js"; +import { type TigerAuthenticatedCallGuard } from "../../../types/index.js"; +import { buildFilterQuery } from "../../common/filtering.js"; +import { buildSortQuery } from "../../common/sorting.js"; + +export class ComputedAttributesQuery implements IComputedAttributesQuery { + private size = 50; + private page = 0; + private filter: IFilterBaseOptions | undefined = undefined; + private sort: string[] | undefined = undefined; + private include: EntitiesApiGetAllEntitiesComputedAttributesRequest["include"] = undefined; + private origin: ObjectOrigin | undefined = undefined; + private method: QueryMethod = "GET"; + private totalCount: number | undefined = undefined; + + constructor( + public readonly authCall: TigerAuthenticatedCallGuard, + private requestParameters: EntitiesApiGetAllEntitiesComputedAttributesRequest, + ) {} + + private setTotalCount = (value?: number) => { + this.totalCount = value; + }; + + withSize(size: number): IComputedAttributesQuery { + this.size = size; + return this; + } + + withPage(page: number): IComputedAttributesQuery { + this.page = page; + return this; + } + + withFilter(filter: IFilterBaseOptions): IComputedAttributesQuery { + this.filter = filter; + // We need to reset total count whenever filter changes + this.setTotalCount(undefined); + return this; + } + + withSorting(sort: string[]): IComputedAttributesQuery { + this.sort = sort; + return this; + } + + withInclude(include: string[]): IComputedAttributesQuery { + // NOTE: Unsupported include values handling is delegated to the backend + this.include = include as EntitiesApiGetAllEntitiesComputedAttributesRequest["include"]; + return this; + } + + withOrigin(origin: ObjectOrigin): IComputedAttributesQuery { + this.origin = origin; + return this; + } + + withMethod(method: QueryMethod): IComputedAttributesQuery { + this.method = method; + return this; + } + + query(): Promise { + return ServerPaging.for( + async ({ limit, offset }) => { + const filterOptions: IFilterBaseOptions = this.filter ?? {}; + const filterQuery = buildFilterQuery(filterOptions); + + /** + * For backend performance reasons, we do not want to ask for paging info each time. + */ + const metaInclude: EntitiesApiGetAllEntitiesComputedAttributesRequest["metaInclude"] = + this.totalCount === undefined ? (["page"] as const) : undefined; + + const items = await this.authCall((client) => { + if (this.method === "POST") { + return EntitiesApi_SearchEntitiesComputedAttributes(client.axios, client.basePath, { + workspaceId: this.requestParameters.workspaceId, + origin: this.origin, + entitySearchBody: { + sort: buildSortQuery(this.sort), + filter: filterQuery, + include: this.include, + metaInclude, + page: { + index: offset / limit, + size: limit, + }, + }, + }); + } + + return EntitiesApi_GetAllEntitiesComputedAttributes(client.axios, client.basePath, { + ...this.requestParameters, + sort: this.sort, + filter: filterQuery, + include: this.include, + metaInclude, + origin: this.origin, + size: limit, + page: offset / limit, + }); + }) + .then((res) => MetadataUtilities.filterValidEntities(res.data)) + .then((data) => { + const totalCount = data.meta?.page?.totalElements; + if (!(totalCount === null || totalCount === undefined)) { + this.setTotalCount(totalCount); + } + return convertComputedAttributesWithLinks(data); + }); + + return { items, totalCount: this.totalCount! }; + }, + this.size, + this.page * this.size, + ); + } +} diff --git a/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/index.ts new file mode 100644 index 00000000000..8855720b44f --- /dev/null +++ b/libs/sdk-backend-tiger/src/backend/workspace/computedAttributes/index.ts @@ -0,0 +1,171 @@ +// (C) 2026 GoodData Corporation + +import { + EntitiesApi_CreateEntityComputedAttributes, + EntitiesApi_DeleteEntityComputedAttributes, + EntitiesApi_GetEntityComputedAttributes, + EntitiesApi_PatchEntityComputedAttributes, + EntitiesApi_UpdateEntityComputedAttributes, +} from "@gooddata/api-client-tiger/endpoints/entitiesObjects"; +import type { + IGetComputedAttributeOptions, + IMeasureExpressionToken, + IWorkspaceComputedAttributesService, +} from "@gooddata/sdk-backend-spi"; +import { + type IComputedAttributeMetadataObject, + type IComputedAttributeMetadataObjectDefinition, + type IMetadataObjectBase, + type IMetadataObjectIdentity, + type ObjRef, + isIdentifierRef, +} from "@gooddata/sdk-model"; + +import { convertComputedAttributeFromBackend } from "../../../convertors/fromBackend/ComputedAttributeConverter.js"; +import { convertComputedAttributeToBackend } from "../../../convertors/toBackend/ComputedAttributeConverter.js"; +import { type TigerAuthenticatedCallGuard } from "../../../types/index.js"; +import { objRefToIdentifier } from "../../../utils/api.js"; +import { resolveExpressionToken, tokenizeExpression } from "../measures/measureExpressionTokens.js"; + +import { ComputedAttributesQuery } from "./computedAttributesQuery.js"; + +export class TigerWorkspaceComputedAttributes implements IWorkspaceComputedAttributesService { + constructor( + private readonly authCall: TigerAuthenticatedCallGuard, + public readonly workspace: string, + ) {} + + async createComputedAttribute( + computedAttribute: IComputedAttributeMetadataObjectDefinition, + ): Promise { + const attributes = convertComputedAttributeToBackend(computedAttribute); + const result = await this.authCall((client) => { + return EntitiesApi_CreateEntityComputedAttributes(client.axios, client.basePath, { + workspaceId: this.workspace, + jsonApiComputedAttributePostOptionalIdDocument: { + data: { + id: computedAttribute.id, + type: "computedAttribute", + attributes, + }, + }, + }); + }); + + return convertComputedAttributeFromBackend(result.data, result.data.included); + } + + async updateComputedAttribute( + computedAttribute: IComputedAttributeMetadataObject, + ): Promise { + const objectId = objRefToIdentifier(computedAttribute.ref, this.authCall); + const attributes = convertComputedAttributeToBackend(computedAttribute); + const result = await this.authCall((client) => { + return EntitiesApi_UpdateEntityComputedAttributes(client.axios, client.basePath, { + objectId, + workspaceId: this.workspace, + jsonApiComputedAttributeInDocument: { + data: { + id: objectId, + type: "computedAttribute", + attributes, + }, + }, + }); + }); + + return convertComputedAttributeFromBackend(result.data, result.data.included); + } + + async updateComputedAttributeMeta( + computedAttribute: Partial & IMetadataObjectIdentity, + ): Promise { + const objectId = objRefToIdentifier(computedAttribute.ref, this.authCall); + const result = await this.authCall((client) => { + return EntitiesApi_PatchEntityComputedAttributes(client.axios, client.basePath, { + objectId, + workspaceId: this.workspace, + jsonApiComputedAttributePatchDocument: { + data: { + id: objectId, + type: "computedAttribute", + attributes: { + ...(computedAttribute.title === undefined + ? {} + : { title: computedAttribute.title }), + ...(computedAttribute.description === undefined + ? {} + : { description: computedAttribute.description }), + ...(computedAttribute.tags === undefined ? {} : { tags: computedAttribute.tags }), + ...(computedAttribute.isHidden === undefined + ? {} + : { isHidden: computedAttribute.isHidden }), + }, + }, + }, + }); + }); + + return convertComputedAttributeFromBackend(result.data, result.data.included); + } + + async deleteComputedAttribute(ref: ObjRef): Promise { + const objectId = objRefToIdentifier(ref, this.authCall); + + await this.authCall((client) => { + return EntitiesApi_DeleteEntityComputedAttributes(client.axios, client.basePath, { + objectId, + workspaceId: this.workspace, + }); + }); + } + + public async getComputedAttribute( + ref: ObjRef, + options: IGetComputedAttributeOptions = {}, + ): Promise { + const id = objRefToIdentifier(ref, this.authCall); + const result = await this.authCall((client) => + EntitiesApi_GetEntityComputedAttributes(client.axios, client.basePath, { + objectId: id, + workspaceId: this.workspace, + include: options.loadUserData ? ["createdBy", "modifiedBy"] : [], + }), + ); + + return convertComputedAttributeFromBackend(result.data, result.data.included); + } + + public async getComputedAttributeExpressionTokens(ref: ObjRef): Promise { + if (!isIdentifierRef(ref)) { + throw new Error("only identifiers supported"); + } + + const result = await this.authCall((client) => + EntitiesApi_GetEntityComputedAttributes(client.axios, client.basePath, { + objectId: ref.identifier, + workspaceId: this.workspace, + include: [ + "facts", + "metrics", + "attributes", + "labels", + "datasets", + "parameters", + "computedAttributes", + ], + }), + ); + + const computedAttribute = result.data; + const maql = computedAttribute.data.attributes.content.maql || ""; + + return tokenizeExpression(maql).map((regexToken) => + resolveExpressionToken(regexToken, computedAttribute.included ?? [], computedAttribute.data.id), + ); + } + + public getComputedAttributesQuery(): ComputedAttributesQuery { + return new ComputedAttributesQuery(this.authCall, { workspaceId: this.workspace }); + } +} diff --git a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.test.ts b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.test.ts index 48bc7157fe4..d1fb4a05a3b 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.test.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.test.ts @@ -141,7 +141,7 @@ describe("ChatConversationThreadQuery.stream", () => { userQuestion: "Hello", }); - const reader = query.stream().getReader(); + const reader = query.stream([]).getReader(); const firstEvent = await reader.read(); expect(firstEvent.done).toBe(false); @@ -195,7 +195,7 @@ describe("ChatConversationThreadQuery userContext conversion", () => { }, }); - query.stream(); + query.stream([]); const request = vi.mocked(GenAiApi_PostMessages).mock.calls[0][2]; const widgets = request.aiSendMessageRequest.userContext?.view?.dashboard?.widgets; @@ -248,7 +248,7 @@ describe("ChatConversationThreadQuery userContext conversion", () => { }, }); - query.stream(); + query.stream([]); const request = vi.mocked(GenAiApi_PostMessages).mock.calls[0][2]; const widget = request.aiSendMessageRequest.userContext?.view?.dashboard?.widgets?.[0]; @@ -282,7 +282,7 @@ describe("ChatConversationThreadQuery userContext conversion", () => { }, }); - query.stream(); + query.stream([]); const request = vi.mocked(GenAiApi_PostMessages).mock.calls[0][2]; const widget = request.aiSendMessageRequest.userContext?.view?.dashboard?.widgets?.[0]; @@ -305,7 +305,7 @@ describe("ChatConversationThreadQuery userContext conversion", () => { }, }); - query.stream(); + query.stream([]); const request = vi.mocked(GenAiApi_PostMessages).mock.calls[0][2]; const dashboard = request.aiSendMessageRequest.userContext?.view?.dashboard; @@ -327,7 +327,7 @@ describe("ChatConversationThreadQuery userContext conversion", () => { }, }); - query.stream(); + query.stream([]); const request = vi.mocked(GenAiApi_PostMessages).mock.calls[0][2]; const dashboard = request.aiSendMessageRequest.userContext?.view?.dashboard; diff --git a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.ts b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.ts index 51b14368fde..f7f809204ec 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/genAI/ChatConversations.ts @@ -410,9 +410,9 @@ export class ChatConversationThreadQuery implements IChatConversationThreadQuery effort, }); } - stream(): ReadableStream< - IChatConversationItem | IChatConversationError | IChatConversationInteractionStep - > { + stream( + history: IChatConversationItem[], + ): ReadableStream { // We are using Axios <1.7, which does not support streaming, // as it can't use fetch API instead of XHR. // This method can be simplified once we upgrade to Axios >=1.7. @@ -494,7 +494,9 @@ export class ChatConversationThreadQuery implements IChatConversationThreadQuery return textStream .pipeThrough(new EventSourceParserStream()) .pipeThrough(new ServerSentEventsDataParser()) - .pipeThrough(new ServerSentEventsDataConverter(this.dateNormalizer, () => responseTraceId)); + .pipeThrough( + new ServerSentEventsDataConverter(this.dateNormalizer, history, () => responseTraceId), + ); } } @@ -536,10 +538,12 @@ class ServerSentEventsDataConverter extends TransformStream< > { constructor( dateNormalizer: DateNormalizer, + history: IChatConversationItem[], traceIdProvider: () => string | undefined, locale?: FormattingLocale, timezone?: string, ) { + const current: IChatConversationItem[] = []; super({ transform(event, controller) { if (event.type === "error") { @@ -550,6 +554,7 @@ class ServerSentEventsDataConverter extends TransformStream< const item = convertChatConversationItemFromBackend( event.data.item as AiConversationItemResponse, undefined, + [...history, ...current], dateNormalizer, locale, timezone, @@ -557,6 +562,7 @@ class ServerSentEventsDataConverter extends TransformStream< // Item is dropped (undefined) when its content type is unrecognized by // this frontend version - do not enqueue anything for it. if (item) { + current.push(item); controller.enqueue(item); } } else if (event.type === "interaction_step" && "step" in event.data) { diff --git a/libs/sdk-backend-tiger/src/backend/workspace/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/index.ts index 18a358e2233..bcad70f1fcf 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/index.ts @@ -18,6 +18,7 @@ import { type IWorkspaceAttributesService, type IWorkspaceAutomationService, type IWorkspaceCatalogFactory, + type IWorkspaceComputedAttributesService, type IWorkspaceDashboardsService, type IWorkspaceDatasetsService, type IWorkspaceDescriptor, @@ -54,6 +55,7 @@ import { TigerAttributeHierarchiesService } from "./attributeHierarchies/index.j import { TigerWorkspaceAttributes } from "./attributes/index.js"; import { TigerWorkspaceAutomationService } from "./automations/index.js"; import { TigerWorkspaceCatalogFactory } from "./catalog/factory.js"; +import { TigerWorkspaceComputedAttributes } from "./computedAttributes/index.js"; import { GET_OPTIMIZED_WORKSPACE_PARAMS } from "./constants.js"; import { TigerWorkspaceDashboards } from "./dashboards/index.js"; import { TigerDataFiltersService } from "./dataFilters/index.js"; @@ -174,6 +176,10 @@ export class TigerWorkspace implements IAnalyticalWorkspace { return new TigerWorkspaceFacts(this.authCall, this.workspace); } + public computedAttributes(): IWorkspaceComputedAttributesService { + return new TigerWorkspaceComputedAttributes(this.authCall, this.workspace); + } + public styling(): IWorkspaceStylingService { return new TigerWorkspaceStyling(this.authCall, this.workspace); } diff --git a/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts b/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts index b447970ef9e..976a0a6c217 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/measures/index.ts @@ -2,12 +2,6 @@ import { type AfmValidObjectsQuery, - type JsonApiAttributeOut, - type JsonApiFactOut, - type JsonApiLabelOut, - type JsonApiMetricOut, - type JsonApiMetricOutDocument, - type JsonApiParameterOut, type KeyDriversDimension, MetadataUtilities, } from "@gooddata/api-client-tiger"; @@ -41,8 +35,6 @@ import { type IMetadataObjectIdentity, type IObjectCertificationWrite, type ObjRef, - type ObjectType, - idRef, isIdentifierRef, } from "@gooddata/sdk-model"; @@ -54,7 +46,7 @@ import { convertMetricToBackend } from "../../../convertors/toBackend/MetricConv import { type TigerAuthenticatedCallGuard } from "../../../types/index.js"; import { objRefToIdentifier } from "../../../utils/api.js"; -import { type IExpressionToken, tokenizeExpression } from "./measureExpressionTokens.js"; +import { resolveExpressionToken, tokenizeExpression } from "./measureExpressionTokens.js"; import { MeasuresQuery } from "./measuresQuery.js"; const findDimensionality = ( @@ -123,74 +115,24 @@ export class TigerWorkspaceMeasures implements IWorkspaceMeasuresService { EntitiesApi_GetEntityMetrics(client.axios, client.basePath, { objectId: ref.identifier, workspaceId: this.workspace, - include: ["facts", "metrics", "attributes", "labels", "datasets", "parameters"], + include: [ + "facts", + "metrics", + "attributes", + "labels", + "datasets", + "parameters", + "computedAttributes", + ], }), ); const metric = metricMetadata.data; const maql = metric.data.attributes.content.maql || ""; const regexTokens = tokenizeExpression(maql); - return regexTokens.map((regexToken) => this.resolveToken(regexToken, metric)); - } - - private resolveToken( - regexToken: IExpressionToken, - metric: JsonApiMetricOutDocument, - ): IMeasureExpressionToken { - if ( - regexToken.type === "text" || - regexToken.type === "quoted_text" || - regexToken.type === "comment" || - regexToken.type === "number" || - regexToken.type === "bracket" - ) { - return { type: regexToken.type, value: regexToken.value }; - } - const [type, id] = regexToken.value.split("/"); - if ( - type === "metric" || - type === "fact" || - type === "attribute" || - type === "label" || - type === "dataset" || - type === "parameter" - ) { - return this.resolveObjectToken(id, type, metric.included || [], metric.data.id); - } - throw new Error(`Cannot resolve title of object type ${type}`); - } - - private resolveObjectToken( - objectId: string, - objectType: "metric" | "fact" | "attribute" | "label" | "dataset" | "parameter", - includedObjects: ReadonlyArray, - identifier: string, - ): IMeasureExpressionToken { - const includedObject = includedObjects.find((includedObject) => { - return includedObject.id === objectId && includedObject.type === objectType; - }) as JsonApiMetricOut | JsonApiLabelOut | JsonApiAttributeOut | JsonApiFactOut | JsonApiParameterOut; - - interface ITypeMapping { - [tokenObjectType: string]: ObjectType; - } - const typeMapping: ITypeMapping = { - metric: "measure", - fact: "fact", - attribute: "attribute", - label: "attribute", - dataset: "dataSet", - parameter: "parameter", - }; - - const value = includedObject?.attributes?.title || `${objectType}/${objectId}`; - const token: IMeasureExpressionToken = { - type: typeMapping[objectType], - value, - id: objectId, - ref: idRef(identifier), - }; - - return token; + return regexTokens.map((regexToken) => + resolveExpressionToken(regexToken, metric.included ?? [], metric.data.id), + ); } async createMeasure(measure: IMeasureMetadataObjectDefinition): Promise { diff --git a/libs/sdk-backend-tiger/src/backend/workspace/measures/measureExpressionTokens.ts b/libs/sdk-backend-tiger/src/backend/workspace/measures/measureExpressionTokens.ts index 41636683051..3c68dddd82b 100644 --- a/libs/sdk-backend-tiger/src/backend/workspace/measures/measureExpressionTokens.ts +++ b/libs/sdk-backend-tiger/src/backend/workspace/measures/measureExpressionTokens.ts @@ -1,5 +1,8 @@ // (C) 2019-2026 GoodData Corporation +import { type IMeasureExpressionToken } from "@gooddata/sdk-backend-spi"; +import { type ObjectType, idRef } from "@gooddata/sdk-model"; + export type ExpressionTokenType = | "text" | "quoted_text" @@ -8,6 +11,7 @@ export type ExpressionTokenType = | "fact" | "metric" | "attribute" + | "computed_attribute" | "label" | "dataset" | "parameter" @@ -28,6 +32,9 @@ const TOKEN_TYPE_REGEXP_PAIRS: Array<[ExpressionTokenType, RegExp]> = [ ["metric", /^\{metric\/[^}]*\}/], ["label", /^\{label\/[^}]*\}/], ["attribute", /^\{attribute\/[^}]*\}/], + // computed attributes can be referenced from a metric and from another computed attribute; the + // brace-delimited patterns are distinct literals, so the order among them does not matter + ["computed_attribute", /^\{computed_attribute\/[^}]*\}/], ["dataset", /^\{dataset\/[^}]*\}/], ["parameter", /^\{parameter\/[^}]*\}/], ["comment", /#[^\n]*/], @@ -61,3 +68,76 @@ export const tokenizeExpression = (expression: string): IExpressionToken[] => { value: token.type === "comment" ? token.value : token.value.replace(REMOVE_BRACKETS_REGEXP, ""), })); }; + +/** + * MAQL object types that can be resolved to a title, mapped to the JSON:API type of the included + * object that carries it. They coincide for everything except a computed attribute, whose MAQL + * token is snake_case while its entity type is camelCase. + */ +const INCLUDED_TYPE_BY_TOKEN_TYPE = { + metric: "metric", + fact: "fact", + attribute: "attribute", + label: "label", + dataset: "dataset", + parameter: "parameter", + computed_attribute: "computedAttribute", +} as const; + +type ResolvableTokenType = keyof typeof INCLUDED_TYPE_BY_TOKEN_TYPE; + +const OBJECT_TYPE_BY_TOKEN_TYPE: { [tokenType in ResolvableTokenType]: ObjectType } = { + metric: "measure", + fact: "fact", + attribute: "attribute", + label: "attribute", + dataset: "dataSet", + parameter: "parameter", + computed_attribute: "computedAttribute", +}; + +const isResolvableTokenType = (type: string): type is ResolvableTokenType => + Object.hasOwn(INCLUDED_TYPE_BY_TOKEN_TYPE, type); + +/** + * Resolves one tokenized MAQL fragment into a display token: a referenced object becomes the title + * of the included object it points at, everything else stays verbatim. + * + * Shared by metrics and computed attributes - both are MAQL expressions whose references are + * resolved from the same `included` payload. + * + * @param regexToken - one token out of {@link tokenizeExpression} + * @param included - the `included` array of the entity the expression belongs to + * @param identifier - id of the entity the expression belongs to + */ +export function resolveExpressionToken( + regexToken: IExpressionToken, + included: ReadonlyArray, + identifier: string, +): IMeasureExpressionToken { + if ( + regexToken.type === "text" || + regexToken.type === "quoted_text" || + regexToken.type === "comment" || + regexToken.type === "number" || + regexToken.type === "bracket" + ) { + return { type: regexToken.type, value: regexToken.value }; + } + + const [tokenType, objectId] = regexToken.value.split("/"); + + if (!isResolvableTokenType(tokenType)) { + throw new Error(`Cannot resolve title of object type ${tokenType}`); + } + + const includedType = INCLUDED_TYPE_BY_TOKEN_TYPE[tokenType]; + const includedObject = included.find((object) => object.id === objectId && object.type === includedType); + + return { + type: OBJECT_TYPE_BY_TOKEN_TYPE[tokenType], + value: includedObject?.attributes?.title || `${tokenType}/${objectId}`, + id: objectId, + ref: idRef(identifier), + }; +} diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/CatalogConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/CatalogConverter.ts index 15b1b239206..1d4e2878ea7 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/CatalogConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/CatalogConverter.ts @@ -3,6 +3,7 @@ import { type JsonApiAttributeOutWithLinks, type JsonApiComputedAttributeOutIncludes, + type JsonApiComputedAttributeOutWithLinks, type JsonApiDatasetOutWithLinks, type JsonApiFactOutWithLinks, type JsonApiLabelOutWithLinks, @@ -13,6 +14,7 @@ import { type IGroupableCatalogItemBuilder, newAttributeDisplayFormMetadataObject, newCatalogAttribute, + newCatalogComputedAttribute, newCatalogDateAttribute, newCatalogDateDataset, newCatalogFact, @@ -21,6 +23,7 @@ import { import { type IAttributeDisplayFormMetadataObject, type ICatalogAttribute, + type ICatalogComputedAttribute, type ICatalogDateAttribute, type ICatalogDateDataset, type ICatalogFact, @@ -31,6 +34,7 @@ import { idRef, } from "@gooddata/sdk-model"; +import { convertComputedAttributeFromBackend } from "./ComputedAttributeConverter.js"; import { convertDataSetItem } from "./DataSetConverter.js"; import { toSdkGranularity } from "./dateGranularityConversions.js"; import { convertLabelType } from "./LabelTypeConverter.js"; @@ -123,6 +127,21 @@ export const convertMeasure = ( ); }; +export const convertComputedAttributeToCatalogItem = ( + computedAttribute: JsonApiComputedAttributeOutWithLinks, + included: JsonApiComputedAttributeOutIncludes[] = [], +): ICatalogComputedAttribute => { + const metadataObject = convertComputedAttributeFromBackend(computedAttribute, included); + + return newCatalogComputedAttribute((catalogCa) => + catalogCa + .computedAttribute(metadataObject) + .defaultDisplayForm(metadataObject.displayForms[0]!) + .displayForms(metadataObject.displayForms) + .modify(commonGroupableCatalogItemModifications(computedAttribute)), + ); +}; + export const convertFact = (fact: JsonApiFactOutWithLinks): ICatalogFact => { return newCatalogFact((catalogF) => catalogF diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/ComputedAttributeConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/ComputedAttributeConverter.ts new file mode 100644 index 00000000000..1d6614f9f74 --- /dev/null +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/ComputedAttributeConverter.ts @@ -0,0 +1,101 @@ +// (C) 2026 GoodData Corporation + +import { + type JsonApiComputedAttributeOut, + type JsonApiComputedAttributeOutDocument, + type JsonApiComputedAttributeOutIncludes, + type JsonApiComputedAttributeOutList, + type JsonApiComputedAttributeOutWithLinks, +} from "@gooddata/api-client-tiger"; +import { + type IAttributeDisplayFormMetadataObject, + type IComputedAttributeMetadataObject, + idRef, +} from "@gooddata/sdk-model"; + +import { convertCertificationFromBackend } from "./CertificationConverter.js"; +import { isInheritedObject } from "./ObjectInheritance.js"; +import { convertUserIdentifier } from "./UsersConverter.js"; + +/** + * Fabricates the single display form of a computed attribute. + * + * A computed attribute has no real labels on the backend. To mimic the structure of a normal + * attribute (and thus be usable in the same UI places), exactly one display form is fabricated + * client-side: it shares the id and title with the computed attribute itself. + */ +export function fabricateComputedAttributeDisplayForm( + id: string, + title: string, + description: string, +): IAttributeDisplayFormMetadataObject { + return { + type: "displayForm", + // The ref carries the COMPUTED ATTRIBUTE type, not "displayForm": this ref is what ends up + // in the insight and what the AFM converter turns into an object qualifier, and the backend + // expects an attribute item to reference a computed attribute by its own type rather than as + // a label (a computed attribute has no real labels). + ref: idRef(id, "computedAttribute"), + id, + uri: id, + title, + description, + production: true, + deprecated: false, + unlisted: false, + attribute: idRef(id, "computedAttribute"), + isDefault: true, + isPrimary: true, + }; +} + +function isJsonApiComputedAttributeOutDocument(obj: unknown): obj is JsonApiComputedAttributeOutDocument { + return (obj as JsonApiComputedAttributeOutDocument).data !== undefined; +} + +export function convertComputedAttributeFromBackend( + data: JsonApiComputedAttributeOutDocument | JsonApiComputedAttributeOutWithLinks, + included: JsonApiComputedAttributeOutIncludes[] = [], +): IComputedAttributeMetadataObject { + const object = isJsonApiComputedAttributeOutDocument(data) ? data.data : data; + const { id, attributes, relationships } = object as JsonApiComputedAttributeOut; + const title = attributes.title ?? ""; + const description = attributes.description ?? ""; + + return { + type: "computedAttribute", + ref: idRef(id, "computedAttribute"), + id, + uri: id, + title, + description, + tags: attributes.tags ?? [], + production: true, + deprecated: false, + unlisted: false, + isHidden: attributes.isHidden, + isLocked: isInheritedObject(object), + expression: attributes.content.maql, + format: attributes.content.format ?? undefined, + metricType: attributes.content.metricType, + dataType: attributes.dataType, + isNullable: attributes.isNullable, + nullValue: attributes.nullValue, + locale: attributes.locale, + displayForms: [fabricateComputedAttributeDisplayForm(id, title, description)], + created: attributes.createdAt ?? undefined, + createdBy: convertUserIdentifier(relationships?.createdBy, included), + updated: attributes.modifiedAt ?? undefined, + updatedBy: convertUserIdentifier(relationships?.modifiedBy, included), + certification: convertCertificationFromBackend( + attributes, + convertUserIdentifier(relationships?.certifiedBy, included), + ), + }; +} + +export function convertComputedAttributesWithLinks( + list: JsonApiComputedAttributeOutList, +): IComputedAttributeMetadataObject[] { + return list.data.map((item) => convertComputedAttributeFromBackend(item, list.included)); +} diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts index e3dbb2cd1f9..4a14dc500b7 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/MetadataConverter.ts @@ -8,6 +8,7 @@ import { type JsonApiAttributeOutDocument, type JsonApiAttributeOutList, type JsonApiAttributeOutWithLinks, + type JsonApiComputedAttributeOutWithLinks, type JsonApiDatasetOutWithLinks, type JsonApiFactOut, type JsonApiFactOutDocument, @@ -43,6 +44,7 @@ import { isInheritedObject } from "./ObjectInheritance.js"; export type MetadataObjectFromApi = | JsonApiAttributeOutWithLinks + | JsonApiComputedAttributeOutWithLinks | JsonApiFactOutWithLinks | JsonApiMetricOutWithLinks | JsonApiLabelOutWithLinks diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts index fb6d61f198c..94a4f460b76 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.test.ts @@ -83,7 +83,7 @@ describe("genAIConvertor", () => { }, }; - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer)!; + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer)!; const whatIfPart = (converted.content as IChatConversationMultipartContent) .parts[0] as IChatConversationWhatIfContent; @@ -148,7 +148,7 @@ describe("genAIConvertor", () => { }); const getFirstResult = (item: AiConversationItemResponse) => { - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer)!; + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer)!; const content = (converted.content as { parts: IChatConversationMultipartPart[] }).parts[0]; if (!isChatConversationSearchContent(content)) { throw new Error("Expected searchResults content"); @@ -271,7 +271,7 @@ describe("genAIConvertor", () => { }, }; - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer)!; + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer)!; expect(converted.content).toEqual({ type: "toolResult", @@ -299,7 +299,7 @@ describe("genAIConvertor", () => { }, }; - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer)!; + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer)!; expect(converted.content).toEqual({ type: "toolResult", @@ -321,7 +321,7 @@ describe("genAIConvertor", () => { content: { type: "somethingNew" } as unknown as AiConversationItemResponse["content"], }; - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer); + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer); expect(converted).toBeUndefined(); expect(errorSpy).toHaveBeenCalled(); @@ -346,7 +346,7 @@ describe("genAIConvertor", () => { }, } as unknown as AiConversationItemResponse; - const converted = convertChatConversationItemFromBackend(item, [], dateNormalizer)!; + const converted = convertChatConversationItemFromBackend(item, [], [], dateNormalizer)!; expect((converted.content as IChatConversationMultipartContent).parts).toEqual([ { type: "text", text: "known part" }, diff --git a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts index cc6c6e29218..b240858678e 100644 --- a/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts +++ b/libs/sdk-backend-tiger/src/convertors/fromBackend/genAIConvertor.ts @@ -1,5 +1,6 @@ // (C) 2024-2026 GoodData Corporation +import fastJsonPatch from "fast-json-patch"; import { v4 as uuidv4 } from "uuid"; import { @@ -10,6 +11,7 @@ import { type AiConversationResponse, type AiConversationResponseList, type AiConversationTurnResponse, + type AiDashboardPatchPart, type AiInteractionStepResponse, type AiKeyDriverAnalysis, type AiSearchObject, @@ -27,6 +29,7 @@ import { type IAlertProposal, type IChatConversation, type IChatConversationContent, + type IChatConversationDashboardContent, type IChatConversationError, type IChatConversationFeedback, type IChatConversationInteractionStep, @@ -55,7 +58,9 @@ import { type ISemanticSearchResultItem, type ITempFilterContext, type IdentifierRef, + type ObjRef, type ObjectType, + areObjRefsEqual, assertNever, } from "@gooddata/sdk-model"; @@ -87,11 +92,18 @@ export function convertChatConversationFromBackend(conversation: AiConversationR export function convertChatConversationItemFromBackend( item: AiConversationItemResponse, responses: AiConversationResponseList["responses"] | undefined, + history: IChatConversationItem[], dateNormalizer: DateNormalizer, locale?: FormattingLocale, timezone?: string, ): IChatConversationItem | undefined { - const content = convertChatConversationContentFromBackend(item.content, dateNormalizer, locale, timezone); + const content = convertChatConversationContentFromBackend( + item.content, + history, + dateNormalizer, + locale, + timezone, + ); if (!content) { return undefined; } @@ -122,10 +134,22 @@ export function convertChatConversationItemsFromBackend( locale?: FormattingLocale, timezone?: string, ): IChatConversationItem[] { + const history: IChatConversationItem[] = []; return items - .map((item) => - convertChatConversationItemFromBackend(item, responses, dateNormalizer, locale, timezone), - ) + .map((itm) => { + const item = convertChatConversationItemFromBackend( + itm, + responses, + history, + dateNormalizer, + locale, + timezone, + ); + if (item) { + history.push(item); + } + return item; + }) .filter((item): item is IChatConversationItem => item !== undefined); } @@ -146,6 +170,7 @@ function convertChatConversationFeedbackFromBackend( function convertChatConversationContentFromBackend( content: AiContent, + history: IChatConversationItem[], dateNormalizer: DateNormalizer, locale?: FormattingLocale, timezone?: string, @@ -220,17 +245,23 @@ function convertChatConversationContentFromBackend( ) : null; - const saved = !!part.saved_dashboard_id; - return { type: "dashboard", - saved, insights, + base: part.dashboard, + saved: part.saved_dashboard_id, dashboard: convertToTemporaryFilterContexts(dashboard), }; } case "dashboardPatch": { - return undefined; + if (!part.patch) { + return undefined; + } + + return { + type: "dashboard", + ...applyDashboardPatch(history, part.patch), + }; } case "kda": return { @@ -641,3 +672,84 @@ function asNonPersistedFilterContext( }, }; } + +// Apply dashboard patch to the items + +function applyDashboardPatch(items: IChatConversationItem[], patch: AiDashboardPatchPart["patch"]) { + if (!patch?.dashboard_id) { + return { + dashboard: null, + insights: null, + }; + } + + const related = collectRelatedItems(items, { + identifier: patch.dashboard_id, + type: "analyticalDashboard", + }); + const last = related[related.length - 1]; + const base = last?.base; + const saved = last?.saved; + const previousInsights = last?.insights ?? []; + + if (!base) { + return { + dashboard: null, + insights: null, + }; + } + + let newDocument: AacDashboard | null = null; + try { + const patchResult = fastJsonPatch.applyPatch( + base as AacDashboard, + patch.operations as readonly fastJsonPatch.Operation[], + undefined, + false, + ); + newDocument = patchResult.newDocument; + } catch (e) { + console.error(e); + return { + dashboard: null, + insights: null, + patchError: e as Error, + }; + } + + const data = newDocument ? yamlDashboardToDeclarative([], newDocument) : null; + + const filters = data?.filterContext + ? convertFilterContextFromBackend(buildFilterContextWrapper(data.filterContext)) + : undefined; + + const insights = + patch.references?.visualizations.map((vis) => { + return visualizationObjectsItemToInsight( + yamlVisualisationToMetadataObject([], vis as AacVisualisation), + ); + }) ?? []; + + const dashboard = data + ? convertDashboard(buildDashboardWrapper(data.dashboard, data.tabFilterContexts, saved), filters) + : null; + + return { + dashboard: convertToTemporaryFilterContexts(dashboard), + insights: [...previousInsights, ...insights], + }; +} + +function collectRelatedItems(items: IChatConversationItem[], ref: ObjRef) { + const related: IChatConversationDashboardContent[] = []; + items.forEach((item) => { + if (item.content.type === "multipart") { + item.content.parts.forEach((part) => { + if (part.type === "dashboard" && part.dashboard && areObjRefsEqual(part.dashboard.ref, ref)) { + related.push(part); + } + }); + } + }); + return related; +} diff --git a/libs/sdk-backend-tiger/src/convertors/toBackend/ComputedAttributeConverter.ts b/libs/sdk-backend-tiger/src/convertors/toBackend/ComputedAttributeConverter.ts new file mode 100644 index 00000000000..f976c58f329 --- /dev/null +++ b/libs/sdk-backend-tiger/src/convertors/toBackend/ComputedAttributeConverter.ts @@ -0,0 +1,26 @@ +// (C) 2026 GoodData Corporation + +import { type JsonApiComputedAttributeInAttributes } from "@gooddata/api-client-tiger"; +import { type IComputedAttributeMetadataObjectDefinition } from "@gooddata/sdk-model"; + +export function convertComputedAttributeToBackend( + computedAttribute: IComputedAttributeMetadataObjectDefinition, +): JsonApiComputedAttributeInAttributes { + return { + title: computedAttribute.title, + description: computedAttribute.description, + content: { + maql: computedAttribute.expression, + format: computedAttribute.format, + ...(typeof computedAttribute.metricType === "undefined" + ? {} + : { metricType: computedAttribute.metricType }), + }, + tags: computedAttribute.tags, + isHidden: computedAttribute.isHidden, + dataType: computedAttribute.dataType, + isNullable: computedAttribute.isNullable, + nullValue: computedAttribute.nullValue, + locale: computedAttribute.locale, + }; +} diff --git a/libs/sdk-backend-tiger/src/convertors/toBackend/InsightConverter.test.ts b/libs/sdk-backend-tiger/src/convertors/toBackend/InsightConverter.test.ts index bc556f33130..5dca0a7eaba 100644 --- a/libs/sdk-backend-tiger/src/convertors/toBackend/InsightConverter.test.ts +++ b/libs/sdk-backend-tiger/src/convertors/toBackend/InsightConverter.test.ts @@ -59,3 +59,47 @@ describe("convertInsight with parameter values", () => { expect(restored.insight.parameters).toEqual(params); }); }); + +describe("convertInsight with a computed attribute", () => { + it("should persist a computed attribute in the buckets by its own type", () => { + // A computed attribute reaches the insight as an attribute whose display form ref carries + // the COMPUTED ATTRIBUTE type - it has no real labels, so the fabricated display form + // points at the computed attribute itself. + const insight: IInsight = { + insight: { + ...emptyInsight.insight, + buckets: [ + { + localIdentifier: "view", + items: [ + { + attribute: { + localIdentifier: "ca1", + displayForm: idRef("rep_performance", "computedAttribute"), + }, + }, + ], + }, + ], + }, + }; + + const tigerObj = convertInsight(insight); + + expect(tigerObj.buckets).toEqual([ + { + localIdentifier: "view", + items: [ + { + attribute: { + localIdentifier: "ca1", + displayForm: { + identifier: { id: "rep_performance", type: "computedAttribute" }, + }, + }, + }, + ], + }, + ]); + }); +}); diff --git a/libs/sdk-backend-tiger/src/types/index.ts b/libs/sdk-backend-tiger/src/types/index.ts index a3d840179cf..5bbd2c9fddf 100644 --- a/libs/sdk-backend-tiger/src/types/index.ts +++ b/libs/sdk-backend-tiger/src/types/index.ts @@ -20,7 +20,14 @@ export type TigerAuthenticatedCallGuard = AuthenticatedCallGuard; */ export type TigerAfmCompatibleObjectType = Extract< TigerCompatibleObjectType, - "attribute" | "measure" | "displayForm" | "dataSet" | "fact" | "variable" + "attribute" | "computedAttribute" | "measure" | "displayForm" | "dataSet" | "fact" | "variable" >; /** @@ -26,6 +26,7 @@ export const tigerIdTypeToObjectType: { [tigerType in TigerObjectType]: TigerCompatibleObjectType; } = { attribute: "attribute", + computedAttribute: "computedAttribute", metric: "measure", label: "displayForm", dataset: "dataSet", @@ -50,6 +51,8 @@ export const objectTypeToTigerIdType = invert(tigerIdTypeToObjectType) as { */ export const objectTypeToTigerAfmType: Record = { attribute: "attribute", + // a computed attribute is referenced by its own type, not as a label - it has no real labels + computedAttribute: "computedAttribute", measure: "metric", displayForm: "label", dataSet: "dataset", diff --git a/libs/sdk-backend-tiger/tests/integrated/catalog.test.ts b/libs/sdk-backend-tiger/tests/integrated/catalog.test.ts index 77bc2024f77..c80d066d7a9 100644 --- a/libs/sdk-backend-tiger/tests/integrated/catalog.test.ts +++ b/libs/sdk-backend-tiger/tests/integrated/catalog.test.ts @@ -4,9 +4,8 @@ import { beforeAll, describe, expect, it } from "vitest"; import { measureLocalId, newArithmeticMeasure, newPopMeasure } from "@gooddata/sdk-model"; -import { WinRate } from "../../src/fixtures/full.js"; - import { sanitizeWorkspace, sortToOrder, testBackend, testWorkspace } from "./backend.js"; +import { WinRate } from "./full.test.helpers.js"; const backend = testBackend(); diff --git a/libs/sdk-backend-tiger/tests/integrated/elements.test.ts b/libs/sdk-backend-tiger/tests/integrated/elements.test.ts index 37435298922..45cdfc42b86 100644 --- a/libs/sdk-backend-tiger/tests/integrated/elements.test.ts +++ b/libs/sdk-backend-tiger/tests/integrated/elements.test.ts @@ -10,9 +10,8 @@ import { newPositiveAttributeFilter, } from "@gooddata/sdk-model"; -import { Account, AccountId, Product } from "../../src/fixtures/full.js"; - import { testBackend, testWorkspace } from "./backend.js"; +import { Account, AccountId, Product } from "./full.test.helpers.js"; import { productName } from "./referenceObjects.test.helpers.js"; const backend = testBackend(); diff --git a/libs/sdk-backend-tiger/src/fixtures/full.ts b/libs/sdk-backend-tiger/tests/integrated/full.test.helpers.ts similarity index 100% rename from libs/sdk-backend-tiger/src/fixtures/full.ts rename to libs/sdk-backend-tiger/tests/integrated/full.test.helpers.ts diff --git a/libs/sdk-code-convertors/api/sdk-code-convertors.api.md b/libs/sdk-code-convertors/api/sdk-code-convertors.api.md index 7ffb5c32ff9..fb598a4d4a3 100644 --- a/libs/sdk-code-convertors/api/sdk-code-convertors.api.md +++ b/libs/sdk-code-convertors/api/sdk-code-convertors.api.md @@ -13,6 +13,7 @@ import type { AttributeHierarchy } from '@gooddata/sdk-code-schemas/v1'; import type { Bucket } from '@gooddata/sdk-code-schemas/v1'; import type { CalculatedMetricField } from '@gooddata/sdk-code-schemas/v1'; import type { Color } from '@gooddata/sdk-code-schemas/v1'; +import type { ComputedAttribute } from '@gooddata/sdk-code-schemas/v1'; import type { ContainerWidget } from '@gooddata/sdk-code-schemas/v1'; import type { Dashboard } from '@gooddata/sdk-code-schemas/v1'; import type { DashboardFilters } from '@gooddata/sdk-code-schemas/v1'; @@ -22,6 +23,7 @@ import type { DateDataset } from '@gooddata/sdk-code-schemas/v1'; import { DeclarativeAnalyticalDashboard } from '@gooddata/api-client-tiger'; import { DeclarativeAttribute } from '@gooddata/api-client-tiger'; import { DeclarativeAttributeHierarchy } from '@gooddata/api-client-tiger'; +import { DeclarativeComputedAttribute } from '@gooddata/api-client-tiger'; import { DeclarativeDashboardPlugin } from '@gooddata/api-client-tiger'; import { DeclarativeDataset } from '@gooddata/api-client-tiger'; import { DeclarativeDateDataset } from '@gooddata/api-client-tiger'; @@ -108,6 +110,9 @@ import { YAMLSeq } from 'yaml'; // @public (undocumented) export type AacAttributeHierarchy = AttributeHierarchy; +// @public (undocumented) +export type AacComputedAttribute = ComputedAttribute; + // @public (undocumented) export type AacDashboard = Dashboard; @@ -1217,6 +1222,9 @@ export function comboChartSave(_fields: Visualisation["query"]["fields"] | undef lineStyleMapping: LineStyleMapping[] | undefined; } | undefined; +// @internal (undocumented) +export const ComputedAttributeTypes: string[]; + // @internal (undocumented) export type ConfigDefaults = { [key in keyof T]: T[key]; @@ -1353,6 +1361,12 @@ export function declarativeAttributeToYaml(def: IAttributeBody, errorContext?: I // @internal (undocumented) export function declarativeBucketsToYaml(entities: FromEntities, buckets: IBucket[], errorContext?: IErrorContext): YamlBuckets; +// @public (undocumented) +export function declarativeComputedAttributeToYaml(computedAttribute: DeclarativeComputedAttribute): { + content: string; + json: ComputedAttribute; +}; + // @public (undocumented) export function declarativeDashboardToYaml(entities: FromEntities, dashboard: DeclarativeAnalyticalDashboard, filterContexts?: DeclarativeFilterContext[], context?: IErrorContext): { content: string; @@ -1375,7 +1389,7 @@ export function declarativeDateInstanceToYaml(dataset: DeclarativeDateDataset): export function declarativeDrillToYaml(drill: InsightDrillDefinition, entities?: FromEntities, sourceVisualizationId?: string, errorContext?: IErrorContext): YAMLMap; // @public -export type DeclarativeEntityData = DeclarativeDataset | DeclarativeDateDataset | DeclarativeMetric | DeclarativeStringParameter | DeclarativeVisualizationObject | DeclarativeDashboardPlugin | DeclarativeAttributeHierarchy | { +export type DeclarativeEntityData = DeclarativeDataset | DeclarativeDateDataset | DeclarativeMetric | DeclarativeComputedAttribute | DeclarativeStringParameter | DeclarativeVisualizationObject | DeclarativeDashboardPlugin | DeclarativeAttributeHierarchy | { dashboard: DeclarativeAnalyticalDashboard; filterContext?: DeclarativeFilterContext; tabFilterContexts?: DeclarativeFilterContext[]; @@ -1677,7 +1691,7 @@ export function donutChartSave(_fields: Visualisation["query"]["fields"] | undef export type EmptyValueHandling = NonNullable; // @public -export type EntityData = Dataset | DateDataset | Metric | Parameter | Visualisation | Dashboard | Plugin_2 | AttributeHierarchy; +export type EntityData = Dataset | DateDataset | Metric | ComputedAttribute | Parameter | Visualisation | Dashboard | Plugin_2 | AttributeHierarchy; // @public (undocumented) export type ExportEntities = Array<{ @@ -4211,6 +4225,9 @@ export function yamlBucketsToDeclarative(entities: ExportEntities, input: Visual attrFilterConfig: IAttributeFilterConfigs; }; +// @public (undocumented) +export function yamlComputedAttributeToDeclarative(input: ComputedAttribute): DeclarativeComputedAttribute; + // @public (undocumented) export function yamlDashboardToDeclarative(entities: ExportEntities, input: Dashboard): { dashboard: DeclarativeAnalyticalDashboard; diff --git a/libs/sdk-code-convertors/package.json b/libs/sdk-code-convertors/package.json index d76c5d6de8d..54b3a7544e6 100644 --- a/libs/sdk-code-convertors/package.json +++ b/libs/sdk-code-convertors/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-code-convertors", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData AAC declarative converters", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-code-convertors/python/pyproject.toml b/libs/sdk-code-convertors/python/pyproject.toml index f944ac30a86..81a77f16e4e 100644 --- a/libs/sdk-code-convertors/python/pyproject.toml +++ b/libs/sdk-code-convertors/python/pyproject.toml @@ -2,7 +2,7 @@ [project] name = "gooddata-code-convertors" -version = "11.54.0a5" +version = "11.54.0a6" description = "GoodData AAC YAML / Declarative API code converters (WASM-powered)" readme = "README.md" license = { file = "LICENSE" } diff --git a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/__init__.py b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/__init__.py index ac65802f666..4d14501c352 100644 --- a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/__init__.py +++ b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/__init__.py @@ -27,6 +27,7 @@ "yaml_dataset_to_declarative", "yaml_date_dataset_to_declarative", "yaml_metric_to_declarative", + "yaml_computed_attribute_to_declarative", "yaml_visualisation_to_declarative", "yaml_dashboard_to_declarative", "yaml_plugin_to_declarative", @@ -35,6 +36,7 @@ "declarative_dataset_to_yaml", "declarative_date_instance_to_yaml", "declarative_metric_to_yaml", + "declarative_computed_attribute_to_yaml", "declarative_visualisation_to_yaml", "declarative_dashboard_to_yaml", "declarative_plugin_to_yaml", @@ -62,6 +64,11 @@ def yaml_metric_to_declarative(*args) -> dict: return _call("yamlMetricToDeclarative", *args) +def yaml_computed_attribute_to_declarative(*args) -> dict: + """Convert a parsed computed attribute YAML dict to a declarative API dict.""" + return _call("yamlComputedAttributeToDeclarative", *args) + + def yaml_visualisation_to_declarative(*args) -> dict: """Convert a parsed visualisation YAML dict to a declarative API dict.""" return _call("yamlVisualisationToDeclarative", *args) @@ -100,6 +107,11 @@ def declarative_metric_to_yaml(*args) -> dict: return _call("declarativeMetricToYaml", *args) +def declarative_computed_attribute_to_yaml(*args) -> dict: + """Convert a declarative computed attribute dict to YAML format.""" + return _call("declarativeComputedAttributeToYaml", *args) + + def declarative_visualisation_to_yaml(*args) -> dict: """Convert a declarative visualisation dict to YAML format.""" return _call("declarativeVisualisationToYaml", *args) diff --git a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/_types.py b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/_types.py index 921dfc4ee8a..c5acfb792cf 100644 --- a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/_types.py +++ b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/_types.py @@ -1,5 +1,5 @@ # (C) 2026 GoodData Corporation -# schema-hash: dd7fd6ed1784480f941225b7c41c043e572cd15b7cc010aede85a1995b9855ca +# schema-hash: 1a228ad9d85d72f6d8675b3fc00d16c7ea093c33b33ae944dc0938e13259225e from __future__ import annotations @@ -25,6 +25,7 @@ "ColorItems", "ColumnOverride", "ComplexColorItem", + "ComputedAttribute", "Condition", "ConditionalFormatting", "Config", @@ -789,6 +790,16 @@ class DashboardMetricValueFilter(TypedDict): QueryDateFilter: TypeAlias = QueryDateFilter1 | QueryDateFilter2 +class ComputedAttribute(TypedDict): + id: Identifier + type: Literal['computed_attribute'] + title: NotRequired[Title] + description: NotRequired[Description] + tags: NotRequired[Tags] + maql: str + locale: NotRequired[str] + + ColorItems: TypeAlias = dict[str, ComplexColorItem] @@ -1882,6 +1893,7 @@ class Visualisation23(TypedDict): Dataset, DateDataset, Metric, + ComputedAttribute, "Dashboard", Plugin, AttributeHierarchy, diff --git a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/pydantic_models.py b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/pydantic_models.py index 978742e58b4..f6bc9ad42c2 100644 --- a/libs/sdk-code-convertors/python/src/gooddata_code_convertors/pydantic_models.py +++ b/libs/sdk-code-convertors/python/src/gooddata_code_convertors/pydantic_models.py @@ -1,5 +1,5 @@ # (C) 2026 GoodData Corporation -# schema-hash: dd7fd6ed1784480f941225b7c41c043e572cd15b7cc010aede85a1995b9855ca +# schema-hash: 1a228ad9d85d72f6d8675b3fc00d16c7ea093c33b33ae944dc0938e13259225e from __future__ import annotations @@ -58,6 +58,8 @@ "ColumnOverride", "Columns", "ComplexColorItem", + "ComputedAttribute", + "ComputedAttribute1", "Condition", "Condition1", "Condition2", @@ -270,7 +272,7 @@ "Type18", "Type20", "Type21", - "Type24", + "Type22", "Type25", "Type26", "Type27", @@ -302,8 +304,8 @@ "Type51", "Type52", "Type53", - "Type56", - "Type57", + "Type54", + "Type55", "Type58", "Type59", "Type60", @@ -331,6 +333,8 @@ "Type80", "Type81", "Type82", + "Type83", + "Type84", "Type9", "Using", "Using1", @@ -1056,6 +1060,10 @@ class QueryRankingFilter(RootModel[QueryRankingFilter1 | QueryRankingFilter2]): root: QueryRankingFilter1 | QueryRankingFilter2 = Field(..., title='Ranking Filter') +class Type20(Enum): + computed_attribute = 'computed_attribute' + + class Using(BaseModel): model_config = ConfigDict( extra='forbid', @@ -1130,7 +1138,7 @@ class ComplexColorItem( ) = Field(..., title='Color') -class Type20(Enum): +class Type21(Enum): dashboard = 'dashboard' @@ -1266,7 +1274,7 @@ class InteractionFilters(BaseModel): include: InteractionFiltersInclude | None = None -class Type21(Enum): +class Type22(Enum): dataset = 'dataset' dataset_1 = 'dataset' @@ -1283,7 +1291,7 @@ class DatasetType2(Enum): auxiliary = 'auxiliary' -class Type24(Enum): +class Type25(Enum): date = 'date' @@ -1319,7 +1327,7 @@ class Granularity1(Enum): FISCAL_MONTH = 'FISCAL_MONTH' -class Type25(Enum): +class Type26(Enum): attribute = 'attribute' @@ -1328,11 +1336,11 @@ class SortDirection(Enum): DESC = 'DESC' -class Type26(Enum): +class Type27(Enum): fact = 'fact' -class Type27(Enum): +class Type28(Enum): aggregated_fact = 'aggregated_fact' @@ -1424,15 +1432,15 @@ class Source(BaseModel): ) -class Type28(Enum): +class Type29(Enum): metric = 'metric' -class Type29(Enum): +class Type30(Enum): parameter = 'parameter' -class Type30(Enum): +class Type31(Enum): STRING = 'STRING' @@ -1449,7 +1457,7 @@ class ParameterAllowedValue(BaseModel): ) -class Type31(Enum): +class Type32(Enum): plugin = 'plugin' @@ -1472,7 +1480,7 @@ class Operator(Enum): CHANGE = 'CHANGE' -class Type32(Enum): +class Type33(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' @@ -1509,7 +1517,7 @@ class Operator1(Enum): CHANGE_1 = 'CHANGE' -class Type33(Enum): +class Type34(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1525,7 +1533,7 @@ class QueryField2(BaseModel): operator: Operator1 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type33 | None = Field( + type: Type34 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1570,7 +1578,7 @@ class Operator2(Enum): CHANGE = 'CHANGE' -class Type34(Enum): +class Type35(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' @@ -1607,7 +1615,7 @@ class Operator3(Enum): CHANGE_1 = 'CHANGE' -class Type35(Enum): +class Type36(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1623,7 +1631,7 @@ class QueryField4(BaseModel): operator: Operator3 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type35 | None = Field( + type: Type36 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1640,7 +1648,7 @@ class Operator4(Enum): CHANGE = 'CHANGE' -class Type36(Enum): +class Type37(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' @@ -1658,7 +1666,7 @@ class Operator5(Enum): CHANGE_1 = 'CHANGE' -class Type37(Enum): +class Type38(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1674,7 +1682,7 @@ class QueryField6(BaseModel): operator: Operator5 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type37 | None = Field( + type: Type38 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1702,7 +1710,7 @@ class Operator6(Enum): CHANGE = 'CHANGE' -class Type38(Enum): +class Type39(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' @@ -1739,7 +1747,7 @@ class Operator7(Enum): CHANGE_1 = 'CHANGE' -class Type39(Enum): +class Type40(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1755,7 +1763,7 @@ class QueryField8(BaseModel): operator: Operator7 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type39 | None = Field( + type: Type40 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1775,7 +1783,7 @@ class Aggregation8(Enum): RUNSUM = 'RUNSUM' -class Type40(Enum): +class Type41(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' @@ -1799,7 +1807,7 @@ class Aggregation9(Enum): RUNSUM_1 = 'RUNSUM' -class Type41(Enum): +class Type42(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1815,7 +1823,7 @@ class QueryField10(BaseModel): operator: Operator7 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type41 | None = Field( + type: Type42 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1843,7 +1851,7 @@ class Operator10(Enum): CHANGE = 'CHANGE' -class Type42(Enum): +class Type43(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1881,7 +1889,7 @@ class Operator11(Enum): CHANGE_1 = 'CHANGE' -class Type43(Enum): +class Type44(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1897,7 +1905,7 @@ class QueryField12(BaseModel): operator: Operator11 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type43 | None = Field( + type: Type44 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1925,7 +1933,7 @@ class Operator12(Enum): CHANGE = 'CHANGE' -class Type44(Enum): +class Type45(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_PERIOD_1 = 'PREVIOUS_PERIOD' @@ -1963,7 +1971,7 @@ class Operator13(Enum): CHANGE_1 = 'CHANGE' -class Type45(Enum): +class Type46(Enum): PREVIOUS_YEAR = 'PREVIOUS_YEAR' PREVIOUS_PERIOD = 'PREVIOUS_PERIOD' PREVIOUS_YEAR_1 = 'PREVIOUS_YEAR' @@ -1979,7 +1987,7 @@ class QueryField14(BaseModel): operator: Operator13 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type45 | None = Field( + type: Type46 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -1988,7 +1996,7 @@ class QueryField14(BaseModel): ) -class Type46(Enum): +class Type47(Enum): attribute_sort = 'attribute_sort' @@ -2001,7 +2009,7 @@ class Aggregation14(Enum): SUM = 'SUM' -class Type47(Enum): +class Type48(Enum): metric_sort = 'metric_sort' @@ -2044,7 +2052,7 @@ class BucketGeoAreaItem(RootModel[str]): root: str = Field(..., title='Geo Area Bucket') -class Type48(Enum): +class Type49(Enum): SUM = 'SUM' AVG = 'AVG' MAX = 'MAX' @@ -2057,21 +2065,25 @@ class BucketLocationItem(RootModel[str]): root: str = Field(..., title='Location Bucket') -class Type49(Enum): +class Type50(Enum): pushpin = 'pushpin' area = 'area' -class Type50(Enum): +class Type51(Enum): attribute_hierarchy = 'attribute_hierarchy' +class Type52(Enum): + computed_attribute = 'computed_attribute' + + class DataLabelsStyle(Enum): auto = 'auto' backplate = 'backplate' -class Type51(Enum): +class Type53(Enum): solid = 'solid' pattern = 'pattern' outline = 'outline' @@ -2105,7 +2117,7 @@ class PatternNameMapping(Enum): class ChartFill(BaseModel): - type: Type51 | None = None + type: Type53 | None = None pattern_name_mapping: dict[str, PatternNameMapping] | None = None @@ -2418,11 +2430,11 @@ class ConditionalFormatting(BaseModel): ) -class Type52(Enum): +class Type54(Enum): dashboard = 'dashboard' -class Type53(Enum): +class Type55(Enum): dataset = 'dataset' dataset_1 = 'dataset' @@ -2439,7 +2451,7 @@ class DatasetType5(Enum): auxiliary = 'auxiliary' -class Type56(Enum): +class Type58(Enum): date = 'date' @@ -2479,15 +2491,15 @@ class Description(RootModel[constr(max_length=10000)]): root: constr(max_length=10000) -class Type57(Enum): +class Type59(Enum): metric = 'metric' -class Type58(Enum): +class Type60(Enum): parameter = 'parameter' -class Type59(Enum): +class Type61(Enum): plugin = 'plugin' @@ -2495,95 +2507,95 @@ class Title(RootModel[constr(max_length=255)]): root: constr(max_length=255) -class Type60(Enum): +class Type62(Enum): table = 'table' -class Type61(Enum): +class Type63(Enum): bar_chart = 'bar_chart' -class Type62(Enum): +class Type64(Enum): column_chart = 'column_chart' -class Type63(Enum): +class Type65(Enum): line_chart = 'line_chart' -class Type64(Enum): +class Type66(Enum): area_chart = 'area_chart' -class Type65(Enum): +class Type67(Enum): scatter_chart = 'scatter_chart' -class Type66(Enum): +class Type68(Enum): bubble_chart = 'bubble_chart' -class Type67(Enum): +class Type69(Enum): pie_chart = 'pie_chart' -class Type68(Enum): +class Type70(Enum): donut_chart = 'donut_chart' -class Type69(Enum): +class Type71(Enum): treemap_chart = 'treemap_chart' -class Type70(Enum): +class Type72(Enum): pyramid_chart = 'pyramid_chart' -class Type71(Enum): +class Type73(Enum): funnel_chart = 'funnel_chart' -class Type72(Enum): +class Type74(Enum): heatmap_chart = 'heatmap_chart' -class Type73(Enum): +class Type75(Enum): bullet_chart = 'bullet_chart' -class Type74(Enum): +class Type76(Enum): waterfall_chart = 'waterfall_chart' -class Type75(Enum): +class Type77(Enum): dependency_wheel_chart = 'dependency_wheel_chart' -class Type76(Enum): +class Type78(Enum): sankey_chart = 'sankey_chart' -class Type77(Enum): +class Type79(Enum): headline_chart = 'headline_chart' -class Type78(Enum): +class Type80(Enum): combo_chart = 'combo_chart' -class Type79(Enum): +class Type81(Enum): geo_chart = 'geo_chart' -class Type80(Enum): +class Type82(Enum): geo_area_chart = 'geo_area_chart' -class Type81(Enum): +class Type83(Enum): repeater_chart = 'repeater_chart' -class Type82(Enum): +class Type84(Enum): radar_chart = 'radar_chart' @@ -2801,6 +2813,36 @@ class QueryDateFilter(RootModel[QueryDateFilter1 | QueryDateFilter2]): root: QueryDateFilter1 | QueryDateFilter2 = Field(..., title='Date Filter') +class ComputedAttribute1(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + id: Identifier = Field( + ..., + description='A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.', + ) + type: Type20 + title: Title | None = Field( + None, + description='An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly.', + ) + description: Description | None = Field( + None, description='An optional description of the computed attribute.' + ) + tags: Tags | None = Field( + None, + description='A list of strings - metadata tags of this computed attribute.', + ) + maql: str = Field( + ..., + description='Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.', + ) + locale: str | None = Field( + None, + description='An optional locale whose collation order the computed values are sorted by.', + ) + + class ColorItems(RootModel[dict[str, ComplexColorItem]]): root: dict[str, ComplexColorItem] @@ -2918,7 +2960,7 @@ class DateDataset1(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the date instance.') - type: Type24 + type: Type25 title: Title | None = Field( None, description='An optional human readable title for the date instance. Will be derived from id if not provided explicitly.', @@ -2972,7 +3014,7 @@ class Fact(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type26 + type: Type27 title: Title | None = Field( None, description='A human readable title of the field. Optional, derived from id if not provided explicitly.', @@ -3011,7 +3053,7 @@ class AggregatedFact(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type27 + type: Type28 description: Description | None = Field( None, description='An optional description of the field.' ) @@ -3095,7 +3137,7 @@ class Metric1(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the metric.') - type: Type28 + type: Type29 title: Title | None = Field( None, description='An optional human readable title for the metric. Will be derived from id if not provided explicitly.', @@ -3140,7 +3182,7 @@ class StringParameterDefinition(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type30 + type: Type31 defaultValue: str = Field( ..., description='The value used whenever the parameter is not overridden.' ) @@ -3156,7 +3198,7 @@ class Plugin1(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the plugin.') - type: Type31 + type: Type32 title: Title | None = Field( None, description='An optional human readable title for the plugin. Will be derived from id if not provided explicitly.', @@ -3191,7 +3233,7 @@ class QueryField1(BaseModel): operator: Operator | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type32 | None = Field( + type: Type33 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -3217,7 +3259,7 @@ class QueryField7(BaseModel): operator: Operator6 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type38 | None = Field( + type: Type39 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -3239,7 +3281,7 @@ class QueryField9(BaseModel): operator: Operator7 = Field( ..., description='Arithmetic operator to use for this field.' ) - type: Type40 | None = Field( + type: Type41 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -3261,7 +3303,7 @@ class QueryField11(BaseModel): operator: Operator10 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type42 = Field( + type: Type43 = Field( ..., description='Type of relative period metric related to another metric in list.', ) @@ -3281,7 +3323,7 @@ class QueryField13(BaseModel): operator: Operator12 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type44 = Field( + type: Type45 = Field( ..., description='Type of relative period metric related to another metric in list.', ) @@ -3296,7 +3338,7 @@ class QueryAttributeSort(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type46 + type: Type47 by: str | AttributeIdentifier | LabelIdentifier = Field( ..., description='Local attribute or label to use in this sort.' ) @@ -3325,7 +3367,7 @@ class QueryMetricSort(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type47 + type: Type48 direction: Direction = Field(..., description='Sort direction.') metrics: list[str | Metrics] = Field(..., min_length=1) @@ -3341,7 +3383,7 @@ class TotalItem(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type48 + type: Type49 title: Title | None = Field(None, description='A total title.') using: str = Field( ..., description='Local metric identifier to use for this total.' @@ -3355,7 +3397,7 @@ class AttributeHierarchy(BaseModel): id: Identifier = Field( ..., description='A unique identifier of the attribute hierarchy.' ) - type: Type50 + type: Type51 title: Title | None = Field( None, description='An optional human readable title for the attribute hierarchy. Will be derived from id if not provided explicitly.', @@ -3374,6 +3416,36 @@ class AttributeHierarchy(BaseModel): ) +class ComputedAttribute(BaseModel): + model_config = ConfigDict( + extra='forbid', + ) + id: Identifier = Field( + ..., + description='A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.', + ) + type: Type52 + title: Title | None = Field( + None, + description='An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly.', + ) + description: Description | None = Field( + None, description='An optional description of the computed attribute.' + ) + tags: Tags | None = Field( + None, + description='A list of strings - metadata tags of this computed attribute.', + ) + maql: str = Field( + ..., + description='Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.', + ) + locale: str | None = Field( + None, + description='An optional locale whose collation order the computed values are sorted by.', + ) + + class Config(BaseModel): widths: list[WidthItem] | None = Field( None, description='A list of widths in this visualisation.' @@ -3523,7 +3595,7 @@ class DateDataset(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the date instance.') - type: Type56 + type: Type58 title: Title | None = Field( None, description='An optional human readable title for the date instance. Will be derived from id if not provided explicitly.', @@ -3548,7 +3620,7 @@ class Metric(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the metric.') - type: Type57 + type: Type59 title: Title | None = Field( None, description='An optional human readable title for the metric. Will be derived from id if not provided explicitly.', @@ -3577,7 +3649,7 @@ class Plugin(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the plugin.') - type: Type59 + type: Type61 title: Title | None = Field( None, description='An optional human readable title for the plugin. Will be derived from id if not provided explicitly.', @@ -3692,7 +3764,7 @@ class Attribute(BaseModel): extra='forbid', regex_engine="python-re", ) - type: Type25 + type: Type26 title: Title | None = Field( None, description='A human readable title of the field. Optional, derived from id if not provided explicitly.', @@ -3785,7 +3857,7 @@ class LayerItemBase(BaseModel): None, description='An optional human readable title for the layer. Will be derived from id if not provided explicitly.', ) - type: Type49 | None = Field( + type: Type50 | None = Field( None, description='Type of visualisation for this layer.' ) config: Config | None = Field( @@ -3834,7 +3906,7 @@ class Parameter(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the parameter.') - type: Type58 + type: Type60 title: Title | None = Field( None, description='An optional human readable title for the parameter. Will be derived from id if not provided explicitly.', @@ -3895,7 +3967,7 @@ class Parameter1(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the parameter.') - type: Type29 + type: Type30 title: Title | None = Field( None, description='An optional human readable title for the parameter. Will be derived from id if not provided explicitly.', @@ -3932,7 +4004,7 @@ class QueryField3(BaseModel): operator: Operator2 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type34 | None = Field( + type: Type35 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -3967,7 +4039,7 @@ class QueryField5(BaseModel): operator: Operator4 | None = Field( None, description='Arithmetic operator to use for this field.' ) - type: Type36 | None = Field( + type: Type37 | None = Field( None, description='Type of relative period metric related to another metric in list.', ) @@ -4037,7 +4109,7 @@ class Dataset5(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type53 + type: Type55 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4083,7 +4155,7 @@ class Dataset6(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type53 + type: Type55 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4129,7 +4201,7 @@ class Dataset7(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type53 + type: Type55 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4171,7 +4243,7 @@ class Dataset2(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type21 + type: Type22 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4217,7 +4289,7 @@ class Dataset3(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type21 + type: Type22 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4263,7 +4335,7 @@ class Dataset4(BaseModel): regex_engine="python-re", ) id: Identifier = Field(..., description='A unique identifier of the dataset.') - type: Type21 + type: Type22 title: Title | None = Field( None, description='An optional human readable title for the dataset. Will be derived from id if not provided explicitly.', @@ -4325,7 +4397,7 @@ class Visualisation1(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type60 = Field(..., description='Type of visualisation.') + type: Type62 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4371,7 +4443,7 @@ class Visualisation2(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type61 = Field(..., description='Type of visualisation.') + type: Type63 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4414,7 +4486,7 @@ class Visualisation3(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type62 = Field(..., description='Type of visualisation.') + type: Type64 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4457,7 +4529,7 @@ class Visualisation4(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type63 = Field(..., description='Type of visualisation.') + type: Type65 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4500,7 +4572,7 @@ class Visualisation5(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type64 = Field(..., description='Type of visualisation.') + type: Type66 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4543,7 +4615,7 @@ class Visualisation6(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type65 = Field(..., description='Type of visualisation.') + type: Type67 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4586,7 +4658,7 @@ class Visualisation7(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type66 = Field(..., description='Type of visualisation.') + type: Type68 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4629,7 +4701,7 @@ class Visualisation8(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type67 = Field(..., description='Type of visualisation.') + type: Type69 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4669,7 +4741,7 @@ class Visualisation9(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type68 = Field(..., description='Type of visualisation.') + type: Type70 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4709,7 +4781,7 @@ class Visualisation10(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type69 = Field(..., description='Type of visualisation.') + type: Type71 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4749,7 +4821,7 @@ class Visualisation11(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type70 = Field(..., description='Type of visualisation.') + type: Type72 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4789,7 +4861,7 @@ class Visualisation12(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type71 = Field(..., description='Type of visualisation.') + type: Type73 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4829,7 +4901,7 @@ class Visualisation13(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type72 = Field(..., description='Type of visualisation.') + type: Type74 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4875,7 +4947,7 @@ class Visualisation14(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type73 = Field(..., description='Type of visualisation.') + type: Type75 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4915,7 +4987,7 @@ class Visualisation15(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type74 = Field(..., description='Type of visualisation.') + type: Type76 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -4955,7 +5027,7 @@ class Visualisation16(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type75 = Field(..., description='Type of visualisation.') + type: Type77 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5001,7 +5073,7 @@ class Visualisation17(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type76 = Field(..., description='Type of visualisation.') + type: Type78 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5047,7 +5119,7 @@ class Visualisation18(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type77 = Field(..., description='Type of visualisation.') + type: Type79 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5085,7 +5157,7 @@ class Visualisation19(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type78 = Field(..., description='Type of visualisation.') + type: Type80 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5125,7 +5197,7 @@ class Visualisation20(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type79 = Field(..., description='Type of visualisation.') + type: Type81 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5169,7 +5241,7 @@ class Visualisation21(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type80 = Field(..., description='Type of visualisation.') + type: Type82 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5213,7 +5285,7 @@ class Visualisation22(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type81 = Field(..., description='Type of visualisation.') + type: Type83 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5259,7 +5331,7 @@ class Visualisation23(BaseModel): model_config = ConfigDict( extra='forbid', ) - type: Type82 = Field(..., description='Type of visualisation.') + type: Type84 = Field(..., description='Type of visualisation.') id: Identifier = Field(..., description='A unique identifier of the visualisation.') title: Title | None = Field( None, @@ -5358,7 +5430,7 @@ class Dashboard1(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the dashboard.') - type: Type20 + type: Type21 version: Version | None = Field( None, description='Dashboard model version. "2" (default if omitted) — legacy shape: root-level sections/filters are also mirrored into a default tab, producing a declarative model with duplicated content for backward compatibility with older SDK readers. "3" — clean shape: tabs are the sole source of layout and filters; root sections/filters in YAML are still allowed as an authoring shortcut but are wrapped into a single synthetic tab without duplication. Use "3" for new dashboards; "2" exists to keep existing files round-trippable.', @@ -5481,7 +5553,7 @@ class Dashboard(BaseModel): extra='forbid', ) id: Identifier = Field(..., description='A unique identifier of the dashboard.') - type: Type52 + type: Type54 version: Version | None = Field( None, description='Dashboard model version. "2" (default if omitted) — legacy shape: root-level sections/filters are also mirrored into a default tab, producing a declarative model with duplicated content for backward compatibility with older SDK readers. "3" — clean shape: tabs are the sole source of layout and filters; root sections/filters in YAML are still allowed as an authoring shortcut but are wrapped into a single synthetic tab without duplication. Use "3" for new dashboards; "2" exists to keep existing files round-trippable.', @@ -5549,6 +5621,7 @@ class Metadata( Dataset | DateDataset | Metric + | ComputedAttribute | Dashboard | Plugin | AttributeHierarchy @@ -5560,6 +5633,7 @@ class Metadata( Dataset | DateDataset | Metric + | ComputedAttribute | Dashboard | Plugin | AttributeHierarchy diff --git a/libs/sdk-code-convertors/src/computedAttributeConversion.test.ts b/libs/sdk-code-convertors/src/computedAttributeConversion.test.ts new file mode 100644 index 00000000000..6bcf919a60c --- /dev/null +++ b/libs/sdk-code-convertors/src/computedAttributeConversion.test.ts @@ -0,0 +1,116 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { type DeclarativeComputedAttribute } from "@gooddata/api-client-tiger"; +import type { ComputedAttribute } from "@gooddata/sdk-code-schemas/v1"; + +import { declarativeComputedAttributeToYaml } from "./from/declarativeComputedAttributeToYaml.js"; +import { yamlComputedAttributeToDeclarative } from "./to/yamlComputedAttributeToDeclarative.js"; + +const BUCKETING_MAQL = + 'SELECT CASE WHEN {metric/won_activities} > 100 THEN "High" WHEN {metric/won_activities} > 50 THEN "Mid" ELSE "Low" END BY {label/sales_rep.name}'; + +function makeYaml(overrides: Partial = {}): ComputedAttribute { + return { + type: "computed_attribute", + id: "rep_performance", + maql: BUCKETING_MAQL, + ...overrides, + } as ComputedAttribute; +} + +function makeDeclarative( + overrides: Partial = {}, +): DeclarativeComputedAttribute { + return { + id: "rep_performance", + title: "Rep performance", + description: "", + tags: [], + content: { maql: BUCKETING_MAQL }, + dataType: "STRING", + valueType: "TEXT", + ...overrides, + } as DeclarativeComputedAttribute; +} + +describe("computed attribute conversion", () => { + describe("yamlComputedAttributeToDeclarative", () => { + it("should convert the minimal definition and default the value type", () => { + const result = yamlComputedAttributeToDeclarative(makeYaml()); + + expect(result).toEqual({ + id: "rep_performance", + // derived from the id, because the yaml carries no title + title: "Rep Performance", + description: "", + tags: [], + content: { maql: BUCKETING_MAQL }, + dataType: "STRING", + valueType: "TEXT", + }); + }); + + it("should keep the explicit title, description, tags and locale", () => { + const result = yamlComputedAttributeToDeclarative( + makeYaml({ + title: "Rep performance", + description: "Reps bucketed by won activities", + tags: ["Sales"], + locale: "en-US", + }), + ); + + expect(result).toMatchObject({ + title: "Rep performance", + description: "Reps bucketed by won activities", + tags: ["Sales"], + locale: "en-US", + }); + }); + + it("should omit locale when it is not set", () => { + expect(yamlComputedAttributeToDeclarative(makeYaml())).not.toHaveProperty("locale"); + }); + }); + + describe("declarativeComputedAttributeToYaml", () => { + it("should write the yaml document with the type discriminator and the maql", () => { + const { content, json } = declarativeComputedAttributeToYaml(makeDeclarative()); + + expect(content).toContain("type: computed_attribute"); + expect(content).toContain("id: rep_performance"); + expect(content).toContain("maql:"); + expect(json.type).toEqual("computed_attribute"); + expect(json.maql).toEqual(BUCKETING_MAQL); + }); + + it("should not write out the data and value type defaults", () => { + const { content } = declarativeComputedAttributeToYaml(makeDeclarative()); + + expect(content).not.toContain("dataType"); + expect(content).not.toContain("valueType"); + }); + + it("should write out locale when the backend has one", () => { + const { content, json } = declarativeComputedAttributeToYaml( + makeDeclarative({ locale: "en-US" }), + ); + + expect(content).toContain("locale: en-US"); + expect(json.locale).toEqual("en-US"); + }); + }); + + describe("round trip", () => { + it("should survive declarative -> yaml -> declarative unchanged", () => { + const original = makeDeclarative({ description: "Reps bucketed", tags: ["Sales"] }); + + const { json } = declarativeComputedAttributeToYaml(original); + const result = yamlComputedAttributeToDeclarative(json); + + expect(result).toEqual(original); + }); + }); +}); diff --git a/libs/sdk-code-convertors/src/conts.ts b/libs/sdk-code-convertors/src/conts.ts index 992c4fc5663..441ad39ee6d 100644 --- a/libs/sdk-code-convertors/src/conts.ts +++ b/libs/sdk-code-convertors/src/conts.ts @@ -12,6 +12,9 @@ export const MetricTypes = ["metric"]; /** @internal */ export const ParameterTypes = ["parameter"]; +/** @internal */ +export const ComputedAttributeTypes = ["computed_attribute"]; + /** @internal */ export const DashboardTypes = ["dashboard"]; @@ -54,6 +57,7 @@ export const AllTypes = [ ...DateDatasetTypes, ...MetricTypes, ...ParameterTypes, + ...ComputedAttributeTypes, ...DashboardTypes, ...PluginTypes, ...VisualisationsTypes, diff --git a/libs/sdk-code-convertors/src/from/declarativeComputedAttributeToYaml.ts b/libs/sdk-code-convertors/src/from/declarativeComputedAttributeToYaml.ts new file mode 100644 index 00000000000..7e6f9c2342b --- /dev/null +++ b/libs/sdk-code-convertors/src/from/declarativeComputedAttributeToYaml.ts @@ -0,0 +1,43 @@ +// (C) 2026 GoodData Corporation + +import { Document } from "yaml"; + +import { type DeclarativeComputedAttribute } from "@gooddata/api-client-tiger"; +import type { ComputedAttribute } from "@gooddata/sdk-code-schemas/v1"; + +import { COMPUTED_ATTRIBUTE_COMMENT } from "../utils/texts.js"; +import { entryWithSpace, fillOptionalMetaFields } from "../utils/yamlUtils.js"; + +/** @public */ +export function declarativeComputedAttributeToYaml(computedAttribute: DeclarativeComputedAttribute): { + content: string; + json: ComputedAttribute; +} { + // Create new doc and add mandatory fields right away + const doc = new Document({ + type: "computed_attribute", + id: computedAttribute.id, + }); + + // Add intro comment to the document + doc.commentBefore = COMPUTED_ATTRIBUTE_COMMENT; + + // Add optional meta fields + fillOptionalMetaFields(doc, computedAttribute); + + // Add MAQL field + doc.add(entryWithSpace("maql", (computedAttribute.content as any).maql ?? "")); + + // dataType and valueType are deliberately not written out - they are backend defaults the YAML + // shape does not expose (see yamlComputedAttributeToDeclarative) + if (computedAttribute.locale) { + doc.add(doc.createPair("locale", computedAttribute.locale)); + } + + return { + content: doc.toString({ + lineWidth: 0, + }), + json: doc.toJSON() as ComputedAttribute, + }; +} diff --git a/libs/sdk-code-convertors/src/index.ts b/libs/sdk-code-convertors/src/index.ts index 3f78cbe8ddf..4794393390b 100644 --- a/libs/sdk-code-convertors/src/index.ts +++ b/libs/sdk-code-convertors/src/index.ts @@ -5,6 +5,7 @@ // AAC schema types (curated public surface — isolates api-extractor from generated internals) export type { AacAttributeHierarchy, + AacComputedAttribute, AacDashboard, AacDashboardFilters, AacDataset, @@ -42,6 +43,7 @@ export { yamlDateDatesetToDeclarative } from "./to/yamlDateDatasetToDeclarative. export { yamlMetricToDeclarative } from "./to/yamlMetricToDeclarative.js"; export { yamlParameterToDeclarative } from "./to/yamlParameterToDeclarative.js"; export { isDeclarativeStringParameter, type DeclarativeStringParameter } from "./utils/parameterUtils.js"; +export { yamlComputedAttributeToDeclarative } from "./to/yamlComputedAttributeToDeclarative.js"; export { yamlVisualisationToDeclarative, yamlVisualisationToMetadataObject, @@ -72,6 +74,7 @@ export { declarativeDatasetToYaml } from "./from/declarativeDatasetToYaml.js"; export { declarativeDateInstanceToYaml } from "./from/declarativeDateInstanceToYaml.js"; export { declarativeMetricToYaml } from "./from/declarativeMetricToYaml.js"; export { declarativeParameterToYaml } from "./from/declarativeParameterToYaml.js"; +export { declarativeComputedAttributeToYaml } from "./from/declarativeComputedAttributeToYaml.js"; export { declarativeVisualisationToYaml, declarativeVisTypeToYaml, @@ -131,6 +134,7 @@ export { DateDatasetTypes, MetricTypes, ParameterTypes, + ComputedAttributeTypes, DashboardTypes, PluginTypes, AttributeHierarchyTypes, diff --git a/libs/sdk-code-convertors/src/schemas/types.ts b/libs/sdk-code-convertors/src/schemas/types.ts index d46806ebe89..15def235dd1 100644 --- a/libs/sdk-code-convertors/src/schemas/types.ts +++ b/libs/sdk-code-convertors/src/schemas/types.ts @@ -8,6 +8,7 @@ import type { AttributeHierarchy, + ComputedAttribute, Dashboard, DashboardFilters, Dataset, @@ -25,6 +26,8 @@ import type { /** @public */ export type AacAttributeHierarchy = AttributeHierarchy; /** @public */ +export type AacComputedAttribute = ComputedAttribute; +/** @public */ export type AacDashboard = Dashboard; /** @public */ export type AacDashboardFilters = DashboardFilters; diff --git a/libs/sdk-code-convertors/src/to/yamlComputedAttributeToDeclarative.ts b/libs/sdk-code-convertors/src/to/yamlComputedAttributeToDeclarative.ts new file mode 100644 index 00000000000..76a070b4c4f --- /dev/null +++ b/libs/sdk-code-convertors/src/to/yamlComputedAttributeToDeclarative.ts @@ -0,0 +1,36 @@ +// (C) 2026 GoodData Corporation + +import { type DeclarativeComputedAttribute } from "@gooddata/api-client-tiger"; +import type { ComputedAttribute } from "@gooddata/sdk-code-schemas/v1"; + +import { convertIdToTitle } from "../utils/sharedUtils.js"; + +/** + * A computed attribute is textual for now: the backend does not transfer the value type from + * metadata yet, so every computed attribute is interpreted as a STRING/TEXT one. The YAML shape + * therefore does not expose dataType/valueType and the defaults are filled in here. + */ +const DEFAULT_DATA_TYPE = "STRING"; +const DEFAULT_VALUE_TYPE = "TEXT"; + +/** @public */ +export function yamlComputedAttributeToDeclarative(input: ComputedAttribute): DeclarativeComputedAttribute { + // Assuming it's validated already by the `validate` command and all options are accounted for + const output: DeclarativeComputedAttribute = { + id: input.id, + title: input.title ?? convertIdToTitle(input.id), + description: input.description ?? "", + tags: input.tags ?? [], + content: { + maql: input.maql, + }, + dataType: DEFAULT_DATA_TYPE, + valueType: DEFAULT_VALUE_TYPE, + }; + + if (input.locale !== undefined) { + output.locale = input.locale; + } + + return output; +} diff --git a/libs/sdk-code-convertors/src/types.ts b/libs/sdk-code-convertors/src/types.ts index 21843eb9edf..6febf1b0ccb 100644 --- a/libs/sdk-code-convertors/src/types.ts +++ b/libs/sdk-code-convertors/src/types.ts @@ -5,6 +5,7 @@ import { type AfmObjectIdentifier, type DeclarativeAnalyticalDashboard, type DeclarativeAttributeHierarchy, + type DeclarativeComputedAttribute, type DeclarativeDashboardPlugin, type DeclarativeDataset, type DeclarativeDateDataset, @@ -14,6 +15,7 @@ import { } from "@gooddata/api-client-tiger"; import type { AttributeHierarchy, + ComputedAttribute, Dashboard, Dataset, DateDataset, @@ -40,6 +42,7 @@ export type EntityData = | Dataset | DateDataset | Metric + | ComputedAttribute | Parameter | Visualisation | Dashboard @@ -51,6 +54,7 @@ export type DeclarativeEntityData = | DeclarativeDataset | DeclarativeDateDataset | DeclarativeMetric + | DeclarativeComputedAttribute | DeclarativeStringParameter | DeclarativeVisualizationObject | DeclarativeDashboardPlugin diff --git a/libs/sdk-code-convertors/src/utils/texts.ts b/libs/sdk-code-convertors/src/utils/texts.ts index 4a1bb187261..e5ba604d327 100644 --- a/libs/sdk-code-convertors/src/utils/texts.ts +++ b/libs/sdk-code-convertors/src/utils/texts.ts @@ -14,6 +14,13 @@ export const DATE_INSTANCE_COMMENT = [ " https://www.gooddata.com/developers/cloud-native/doc/cloud/model-data/concepts/dataset/#date-datasets", ].join("\n"); +export const COMPUTED_ATTRIBUTE_COMMENT = [ + ' A computed attribute turns numbers into named groups, for example "Small", "Medium", "Large".', + " Write the break points in MAQL - the first matching branch wins - and use it like any attribute.", + " Read more about MAQL:", + " https://www.gooddata.com/developers/cloud-native/doc/cloud/create-metrics/maql/", +].join("\n"); + export const METRIC_COMMENT = [ " A metric is a computational expression of numerical data (facts or other metrics).", " Use MAQL to create reusable multidimensional queries that combine multiple facts and attributes.", diff --git a/libs/sdk-code-convertors/src/utils/typeGuards.ts b/libs/sdk-code-convertors/src/utils/typeGuards.ts index 5b6b5299f92..eea9a4b1038 100644 --- a/libs/sdk-code-convertors/src/utils/typeGuards.ts +++ b/libs/sdk-code-convertors/src/utils/typeGuards.ts @@ -9,6 +9,7 @@ import type { AttributeSort, CalculatedMetricField, Comparison, + ComputedAttribute, ContainerWidget, DashboardAbsoluteDateFilter, DashboardAttributeFilter, @@ -487,6 +488,7 @@ export function isContainerWidget(obj: unknown): obj is ContainerWidget { const DatasetTypes: Dataset["type"][] = ["dataset"]; const DateDatasetTypes: DateDataset["type"][] = ["date"]; const MetricEntityTypes: Metric["type"][] = ["metric"]; +const ComputedAttributeEntityTypes: ComputedAttribute["type"][] = ["computed_attribute"]; const FactTypes: Fact["type"][] = ["fact"]; export function isDataset(obj: unknown): obj is Dataset { @@ -524,3 +526,13 @@ export function isMetricEntity(obj: unknown): obj is Metric { MetricEntityTypes.includes(obj.type as Metric["type"]), ); } + +export function isComputedAttributeEntity(obj: unknown): obj is ComputedAttribute { + return Boolean( + typeof obj === "object" && + obj && + "id" in obj && + "type" in obj && + ComputedAttributeEntityTypes.includes(obj.type as ComputedAttribute["type"]), + ); +} diff --git a/libs/sdk-code-convertors/wasm/entry.js b/libs/sdk-code-convertors/wasm/entry.js index 5e9efc2f9f9..9936fa84917 100644 --- a/libs/sdk-code-convertors/wasm/entry.js +++ b/libs/sdk-code-convertors/wasm/entry.js @@ -17,12 +17,14 @@ import { buildAfmExecution, declarativeAttributeHierarchyToYaml, declarativeDashboardToYaml, + declarativeComputedAttributeToYaml, declarativeDatasetToYaml, declarativeDateInstanceToYaml, declarativeMetricToYaml, declarativePluginToYaml, declarativeVisualisationToYaml, yamlAttributeHierarchyToDeclarative, + yamlComputedAttributeToDeclarative, yamlDashboardToDeclarative, yamlDatasetToDeclarative, yamlDateDatesetToDeclarative, @@ -35,6 +37,7 @@ const converters = { yamlDatasetToDeclarative, yamlDateDatesetToDeclarative, yamlMetricToDeclarative, + yamlComputedAttributeToDeclarative, yamlVisualisationToDeclarative, yamlDashboardToDeclarative, yamlPluginToDeclarative, @@ -42,6 +45,7 @@ const converters = { declarativeDatasetToYaml, declarativeDateInstanceToYaml, declarativeMetricToYaml, + declarativeComputedAttributeToYaml, declarativeVisualisationToYaml, declarativeDashboardToYaml, declarativePluginToYaml, diff --git a/libs/sdk-code-schemas/api/sdk-code-schemas.api.md b/libs/sdk-code-schemas/api/sdk-code-schemas.api.md index 423d5e1e3c6..489512e5819 100644 --- a/libs/sdk-code-schemas/api/sdk-code-schemas.api.md +++ b/libs/sdk-code-schemas/api/sdk-code-schemas.api.md @@ -61,7 +61,7 @@ interface AreaChart { config?: VisualisationConfig4; description?: string; // (undocumented) - id: Id24; + id: Id25; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -71,7 +71,7 @@ interface AreaChart { show_in_ai_results?: boolean; stack_by?: Bucket[]; // (undocumented) - tags?: Tags17; + tags?: Tags18; title?: string; type: "area_chart"; view_by?: Bucket[]; @@ -197,9 +197,9 @@ interface AttributeHierarchy { attributes: [AttributeIdentifier6, ...AttributeIdentifier6[]]; description?: string; // (undocumented) - id: Id18; + id: Id19; // (undocumented) - tags?: Tags11; + tags?: Tags12; title?: string; // (undocumented) type: "attribute_hierarchy"; @@ -337,7 +337,7 @@ interface BarChart { config?: VisualisationConfig1; description?: string; // (undocumented) - id: Id21; + id: Id22; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -347,7 +347,7 @@ interface BarChart { show_in_ai_results?: boolean; stack_by?: Bucket[]; // (undocumented) - tags?: Tags14; + tags?: Tags15; title?: string; type: "bar_chart"; view_by?: Bucket[]; @@ -374,7 +374,7 @@ interface BubbleChart { config?: VisualisationConfig6; description?: string; // (undocumented) - id: Id26; + id: Id27; // @deprecated (undocumented) is_hidden?: boolean; metrics?: (Bucket | EmptyBucket)[]; @@ -384,7 +384,7 @@ interface BubbleChart { show_in_ai_results?: boolean; size_by?: Bucket[]; // (undocumented) - tags?: Tags19; + tags?: Tags20; title?: string; type: "bubble_chart"; view_by?: Bucket[]; @@ -423,7 +423,7 @@ interface BulletChart { config?: VisualisationConfig13; description?: string; // (undocumented) - id: Id33; + id: Id34; // @deprecated (undocumented) is_hidden?: boolean; metrics?: (Bucket | EmptyBucket)[]; @@ -432,7 +432,7 @@ interface BulletChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags26; + tags?: Tags27; title?: string; type: "bullet_chart"; view_by?: Bucket[]; @@ -522,7 +522,7 @@ interface ColumnChart { config?: VisualisationConfig2; description?: string; // (undocumented) - id: Id22; + id: Id23; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -532,7 +532,7 @@ interface ColumnChart { show_in_ai_results?: boolean; stack_by?: Bucket[]; // (undocumented) - tags?: Tags15; + tags?: Tags16; title?: string; type: "column_chart"; view_by?: Bucket[]; @@ -546,7 +546,7 @@ interface ComboChart { config?: VisualisationConfig18; description?: string; // (undocumented) - id: Id38; + id: Id39; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -555,7 +555,7 @@ interface ComboChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags31; + tags?: Tags32; title?: string; type: "combo_chart"; view_by?: Bucket[]; @@ -619,13 +619,29 @@ type CompositePrimaryKey1 = Id3[]; // @public type CompositePrimaryKey2 = Id5[]; +// Warning: (ae-missing-release-tag) "ComputedAttribute" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +interface ComputedAttribute { + description?: string; + // (undocumented) + id: Id8; + locale?: string; + maql: string; + // (undocumented) + tags?: Tags9; + title?: string; + // (undocumented) + type: "computed_attribute"; +} + // Warning: (ae-missing-release-tag) "ContainerWidget" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) interface ContainerWidget { columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // (undocumented) - container: Id13; + container: Id14; enable_section_headers?: boolean; layout_direction?: "row" | "column"; rows?: number; @@ -647,7 +663,7 @@ interface Dashboard { // (undocumented) filters?: DashboardFilters; // (undocumented) - id: Id8; + id: Id9; permissions?: { VIEW?: Permission; EDIT?: Permission; @@ -655,15 +671,15 @@ interface Dashboard { }; persistent_filters_across_tabs?: boolean; plugins?: ({ - id: Id14; + id: Id15; parameters?: { [k: string]: unknown; }; - } | Id15)[]; + } | Id16)[]; sections?: Section[]; tabs?: Tab[]; // (undocumented) - tags?: Tags9; + tags?: Tags10; // (undocumented) timezone_config?: TimezoneConfig; title?: string; @@ -884,7 +900,7 @@ interface DependencyWheelChart { // (undocumented) from?: Bucket1; // (undocumented) - id: Id35; + id: Id36; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -893,7 +909,7 @@ interface DependencyWheelChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags28; + tags?: Tags29; title?: string; // (undocumented) to?: Bucket2; @@ -1070,7 +1086,7 @@ interface FunnelChart { config?: VisualisationConfig11; description?: string; // (undocumented) - id: Id31; + id: Id32; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -1079,7 +1095,7 @@ interface FunnelChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags24; + tags?: Tags25; title?: string; type: "funnel_chart"; view_by?: Bucket[]; @@ -1098,7 +1114,7 @@ interface GeoAreaChart { config?: VisualisationConfig21; description?: string; // (undocumented) - id: Id41; + id: Id42; // @deprecated (undocumented) is_hidden?: boolean; layers?: LayerItem[]; @@ -1108,7 +1124,7 @@ interface GeoAreaChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags33; + tags?: Tags34; title?: string; type: "geo_area_chart"; view_by?: GeoAreaBucket[]; @@ -1132,7 +1148,7 @@ interface GeoChart { config?: VisualisationConfig19; description?: string; // (undocumented) - id: Id39; + id: Id40; // @deprecated (undocumented) is_hidden?: boolean; layers?: LayerItem[]; @@ -1142,7 +1158,7 @@ interface GeoChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags32; + tags?: Tags33; title?: string; type: "geo_chart"; view_by?: PushpinLocationBucket[]; @@ -1156,7 +1172,7 @@ interface HeadlineChart { config?: VisualisationConfig17; description?: string; // (undocumented) - id: Id37; + id: Id38; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -1165,7 +1181,7 @@ interface HeadlineChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags30; + tags?: Tags31; title?: string; type: "headline_chart"; view_by?: unknown[]; @@ -1180,7 +1196,7 @@ interface HeatmapChart { config?: VisualisationConfig12; description?: string; // (undocumented) - id: Id32; + id: Id33; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -1190,7 +1206,7 @@ interface HeatmapChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags25; + tags?: Tags26; title?: string; type: "heatmap_chart"; view_by?: Bucket[]; @@ -1391,6 +1407,11 @@ type Id42 = string; // @public type Id43 = string; +// Warning: (ae-missing-release-tag) "Id44" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +type Id44 = string; + // Warning: (ae-missing-release-tag) "Id5" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1767,7 +1788,7 @@ interface LineChart { config?: VisualisationConfig3; description?: string; // (undocumented) - id: Id23; + id: Id24; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -1776,7 +1797,7 @@ interface LineChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags16; + tags?: Tags17; title?: string; trend_by?: Bucket[]; type: "line_chart"; @@ -1867,7 +1888,7 @@ interface Metadata1 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata10" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1877,7 +1898,7 @@ interface Metadata10 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata11" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1897,13 +1918,13 @@ interface Metadata13 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata14" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata14 = Dashboard; +type Metadata14 = ComputedAttribute; // Warning: (ae-missing-release-tag) "Metadata15" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1917,13 +1938,13 @@ interface Metadata16 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata17" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata17 = Plugin_2; +type Metadata17 = Dashboard; // Warning: (ae-missing-release-tag) "Metadata18" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1937,18 +1958,18 @@ interface Metadata19 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata2" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata2 = Metadata3 | Metadata6 | Metadata9 | Metadata12 | Metadata15 | Metadata18 | Metadata21 | Metadata24 | Metadata27; +type Metadata2 = Metadata3 | Metadata6 | Metadata9 | Metadata12 | Metadata15 | Metadata18 | Metadata21 | Metadata24 | Metadata27 | Metadata30; // Warning: (ae-missing-release-tag) "Metadata20" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata20 = AttributeHierarchy; +type Metadata20 = Plugin_2; // Warning: (ae-missing-release-tag) "Metadata21" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1962,13 +1983,13 @@ interface Metadata22 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata23" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata23 = Parameter; +type Metadata23 = AttributeHierarchy; // Warning: (ae-missing-release-tag) "Metadata24" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1982,13 +2003,13 @@ interface Metadata25 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata26" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata26 = Visualisation; +type Metadata26 = Parameter; // Warning: (ae-missing-release-tag) "Metadata27" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2002,21 +2023,41 @@ interface Metadata28 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata29" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -type Metadata29 = { - [k: string]: unknown; -}; +type Metadata29 = Visualisation; // Warning: (ae-missing-release-tag) "Metadata3" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public type Metadata3 = Metadata4 & Metadata5; +// Warning: (ae-missing-release-tag) "Metadata30" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +type Metadata30 = Metadata31 & Metadata32; + +// Warning: (ae-missing-release-tag) "Metadata31" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +interface Metadata31 { + // (undocumented) + [k: string]: unknown; + // (undocumented) + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; +} + +// Warning: (ae-missing-release-tag) "Metadata32" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +type Metadata32 = { + [k: string]: unknown; +}; + // Warning: (ae-missing-release-tag) "Metadata4" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -2024,7 +2065,7 @@ interface Metadata4 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata5" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -2044,7 +2085,7 @@ interface Metadata7 { // (undocumented) [k: string]: unknown; // (undocumented) - type: "dataset" | "date" | "metric" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; + type: "dataset" | "date" | "metric" | "computed_attribute" | "dashboard" | "plugin" | "table" | "bar_chart" | "column_chart" | "line_chart" | "area_chart" | "scatter_chart" | "bubble_chart" | "pie_chart" | "donut_chart" | "treemap_chart" | "pyramid_chart" | "funnel_chart" | "heatmap_chart" | "bullet_chart" | "waterfall_chart" | "dependency_wheel_chart" | "sankey_chart" | "headline_chart" | "combo_chart" | "geo_chart" | "geo_area_chart" | "repeater_chart" | "radar_chart" | "attribute_hierarchy" | "parameter"; } // Warning: (ae-missing-release-tag) "Metadata8" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -2398,6 +2439,58 @@ export const metadata_v1: { }; required: string[]; }; + computed_attribute: { + title: string; + type: string; + additionalProperties: boolean; + properties: { + id: { + $ref: string; + description: string; + $semantic: ({ + type: string; + source: string; + code: string; + } | { + code?: undefined; + type: string; + source: string; + })[]; + }; + type: { + type: string; + enum: string[]; + }; + title: { + $ref: string; + description: string; + }; + description: { + $ref: string; + description: string; + }; + tags: { + $ref: string; + description: string; + }; + maql: { + type: string; + description: string; + $semantic: { + type: string; + }; + }; + locale: { + type: string; + description: string; + }; + }; + $semantic: { + type: string; + snippets: string[]; + }; + required: string[]; + }; dashboard: { title: string; type: string; @@ -6619,6 +6712,58 @@ export const metadata_v1: { mode: string; }; }; + computed_attribute: { + title: string; + type: string; + additionalProperties: boolean; + properties: { + id: { + $ref: string; + description: string; + $semantic: ({ + type: string; + source: string; + code: string; + } | { + code?: undefined; + type: string; + source: string; + })[]; + }; + type: { + type: string; + enum: string[]; + }; + title: { + $ref: string; + description: string; + }; + description: { + $ref: string; + description: string; + }; + tags: { + $ref: string; + description: string; + }; + maql: { + type: string; + description: string; + $semantic: { + type: string; + }; + }; + locale: { + type: string; + description: string; + }; + }; + $semantic: { + type: string; + snippets: string[]; + }; + required: string[]; + }; widthItem: { title: string; type: string; @@ -9705,9 +9850,9 @@ interface Parameter { definition: ParameterDefinition; description?: string; // (undocumented) - id: Id19; + id: Id20; // (undocumented) - tags?: Tags12; + tags?: Tags13; title?: string; // (undocumented) type: "parameter"; @@ -9753,7 +9898,7 @@ interface PieChart { config?: VisualisationConfig7; description?: string; // (undocumented) - id: Id27; + id: Id28; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -9762,7 +9907,7 @@ interface PieChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags20; + tags?: Tags21; title?: string; type: "pie_chart"; view_by?: Bucket[]; @@ -9776,7 +9921,7 @@ interface PieChart1 { config?: VisualisationConfig8; description?: string; // (undocumented) - id: Id28; + id: Id29; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -9785,7 +9930,7 @@ interface PieChart1 { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags21; + tags?: Tags22; title?: string; type: "donut_chart"; view_by?: Bucket[]; @@ -9797,9 +9942,9 @@ interface PieChart1 { interface Plugin_2 { description?: string; // (undocumented) - id: Id17; + id: Id18; // (undocumented) - tags?: Tags10; + tags?: Tags11; title?: string; // (undocumented) type: "plugin"; @@ -9895,7 +10040,7 @@ interface PyramidChart { config?: VisualisationConfig10; description?: string; // (undocumented) - id: Id30; + id: Id31; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -9904,7 +10049,7 @@ interface PyramidChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags23; + tags?: Tags24; title?: string; type: "pyramid_chart"; view_by?: Bucket[]; @@ -10218,7 +10363,7 @@ interface RadarChart { config?: VisualisationConfig23; description?: string; // (undocumented) - id: Id43; + id: Id44; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -10227,7 +10372,7 @@ interface RadarChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags35; + tags?: Tags36; title?: string; type: "radar_chart"; view_by?: Bucket[]; @@ -10290,7 +10435,7 @@ interface RepeaterChart { config?: VisualisationConfig22; description?: string; // (undocumented) - id: Id42; + id: Id43; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -10300,7 +10445,7 @@ interface RepeaterChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags34; + tags?: Tags35; title?: string; type: "repeater_chart"; view_by?: Bucket[]; @@ -10313,7 +10458,7 @@ interface RichTextWidget { columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; content: string; // (undocumented) - id?: Id11; + id?: Id12; rows?: number; } @@ -10327,7 +10472,7 @@ interface SankeyChart { // (undocumented) from?: Bucket3; // (undocumented) - id: Id36; + id: Id37; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -10336,7 +10481,7 @@ interface SankeyChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags29; + tags?: Tags30; title?: string; // (undocumented) to?: Bucket4; @@ -10353,7 +10498,7 @@ interface ScatterChart { config?: VisualisationConfig5; description?: string; // (undocumented) - id: Id25; + id: Id26; // @deprecated (undocumented) is_hidden?: boolean; metrics?: (Bucket | EmptyBucket)[]; @@ -10362,7 +10507,7 @@ interface ScatterChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags18; + tags?: Tags19; title?: string; type: "scatter_chart"; view_by?: Bucket[]; @@ -10493,7 +10638,7 @@ interface Tab { // (undocumented) filters?: DashboardFilters1; // (undocumented) - id: Id16; + id: Id17; sections: Section[]; title: string; } @@ -10507,7 +10652,7 @@ interface Table { config?: VisualisationConfig; description?: string; // (undocumented) - id: Id20; + id: Id21; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -10517,7 +10662,7 @@ interface Table { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags13; + tags?: Tags14; title?: string; type: "table"; view_by?: Bucket[]; @@ -10673,6 +10818,11 @@ type Tags34 = string[]; // @public type Tags35 = string[]; +// Warning: (ae-missing-release-tag) "Tags36" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +type Tags36 = string[]; + // Warning: (ae-missing-release-tag) "Tags4" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -10804,7 +10954,7 @@ interface TreemapChart { config?: VisualisationConfig9; description?: string; // (undocumented) - id: Id29; + id: Id30; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -10813,7 +10963,7 @@ interface TreemapChart { segment_by?: Bucket[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags22; + tags?: Tags23; title?: string; type: "treemap_chart"; view_by?: Bucket[]; @@ -10858,10 +11008,14 @@ declare namespace v1 { Metadata14, Id8, Tags9, + Metadata15, + Metadata17, + Id9, + Tags10, Widget, Widget1, - Id9, Id10, + Id11, Interaction, Interaction1, InteractionClickOn, @@ -10881,11 +11035,11 @@ declare namespace v1 { IgnoredDrillDown2, IgnoredDrillDown3, Widget2, - Id11, - Widget3, Id12, - Widget4, + Widget3, Id13, + Widget4, + Id14, DashboardAttributeFilter, DashboardAttributeFilter1, AttributeIdentifier2, @@ -10904,30 +11058,30 @@ declare namespace v1 { AttributeIdentifier5, LabelIdentifier5, DisplayAsLabelIdentifier3, - Id14, Id15, Id16, - Metadata15, - Metadata17, Id17, - Tags10, Metadata18, Metadata20, Id18, Tags11, - AttributeIdentifier6, Metadata21, Metadata23, Id19, Tags12, - ParameterDefinition, - ParameterDefinition1, + AttributeIdentifier6, Metadata24, Metadata26, - Visualisation, - Visualisation1, Id20, Tags13, + ParameterDefinition, + ParameterDefinition1, + Metadata27, + Metadata29, + Visualisation, + Visualisation1, + Id21, + Tags14, Field, AttributeIdentifier7, Field1, @@ -11009,83 +11163,83 @@ declare namespace v1 { Bucket, SimpleBucket, Visualisation2, - Id21, - Tags14, - Visualisation3, Id22, Tags15, - Visualisation4, + Visualisation3, Id23, Tags16, - Visualisation5, + Visualisation4, Id24, Tags17, - Visualisation6, + Visualisation5, Id25, Tags18, - EmptyBucket, - Visualisation7, + Visualisation6, Id26, Tags19, - Visualisation8, + EmptyBucket, + Visualisation7, Id27, Tags20, - Visualisation9, + Visualisation8, Id28, Tags21, - Visualisation10, + Visualisation9, Id29, Tags22, - Visualisation11, + Visualisation10, Id30, Tags23, - Visualisation12, + Visualisation11, Id31, Tags24, - Visualisation13, + Visualisation12, Id32, Tags25, - Visualisation14, + Visualisation13, Id33, Tags26, - Visualisation15, + Visualisation14, Id34, Tags27, - Visualisation16, + Visualisation15, Id35, Tags28, + Visualisation16, + Id36, + Tags29, Bucket1, Bucket2, Visualisation17, - Id36, - Tags29, + Id37, + Tags30, Bucket3, Bucket4, Visualisation18, - Id37, - Tags30, - Visualisation19, Id38, Tags31, - Visualisation20, + Visualisation19, Id39, Tags32, + Visualisation20, + Id40, + Tags33, PushpinLocationBucket, LayerItem, - Id40, + Id41, LocationBucket, GeoAreaBucket, Visualisation21, - Id41, - Tags33, - Visualisation22, Id42, Tags34, - Visualisation23, + Visualisation22, Id43, Tags35, - Metadata27, - Metadata29, + Visualisation23, + Id44, + Tags36, + Metadata30, + Metadata32, Metadata1, Metadata4, NormalDataset, @@ -11108,6 +11262,8 @@ declare namespace v1 { Metadata10, Metric, Metadata13, + ComputedAttribute, + Metadata16, Dashboard, TimezoneConfig, Section, @@ -11137,16 +11293,16 @@ declare namespace v1 { Tab, DashboardFilters1, Permission, - Metadata16, - Plugin_2 as Plugin, Metadata19, - AttributeHierarchy, + Plugin_2 as Plugin, Metadata22, + AttributeHierarchy, + Metadata25, Parameter, StringParameterDefinition, StringParameterConstraints, ParameterAllowedValue, - Metadata25, + Metadata28, Table, Query, Fields3, @@ -11260,7 +11416,7 @@ declare namespace v1 { RadarChart, Query22, VisualisationConfig23, - Metadata28 + Metadata31 } } @@ -18638,11 +18794,11 @@ interface VisualisationConfig9 { interface VisualisationWidget { columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // (undocumented) - date?: Id10; + date?: Id11; // (undocumented) description?: string | false | "inherit"; // (undocumented) - id?: Id9; + id?: Id10; ignored_cross_filtering?: boolean; ignored_drill_downs?: IgnoredDrillDown[]; ignored_drill_downs_intersections?: IgnoredDrillDownIntersection[]; @@ -18662,11 +18818,11 @@ interface VisualisationWidget { interface VisualisationWidget1 { columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // (undocumented) - date?: Id10; + date?: Id11; // (undocumented) description?: string | false | "inherit"; // (undocumented) - id?: Id9; + id?: Id10; ignored_cross_filtering?: boolean; ignored_drill_downs?: IgnoredDrillDown[]; ignored_drill_downs_intersections?: IgnoredDrillDownIntersection[]; @@ -18687,7 +18843,7 @@ interface VisualizationDataLayer { // (undocumented) config?: VisualisationConfig20; // (undocumented) - id: Id40; + id: Id41; metrics?: (Bucket | EmptyBucket)[]; segment_by?: Bucket[]; title?: string; @@ -18701,7 +18857,7 @@ interface VisualizationDataLayer { interface VisualizationSwitcherWidget { columns?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // (undocumented) - id?: Id12; + id?: Id13; rows?: number; visualizations: VisualisationWidget1[]; } @@ -18714,7 +18870,7 @@ interface WaterfallChart { config?: VisualisationConfig14; description?: string; // (undocumented) - id: Id34; + id: Id35; // @deprecated (undocumented) is_hidden?: boolean; metrics?: Bucket[]; @@ -18723,7 +18879,7 @@ interface WaterfallChart { segment_by?: unknown[]; show_in_ai_results?: boolean; // (undocumented) - tags?: Tags27; + tags?: Tags28; title?: string; type: "waterfall_chart"; view_by?: Bucket[]; diff --git a/libs/sdk-code-schemas/package.json b/libs/sdk-code-schemas/package.json index 66574c7d5d5..5317c3dc9d7 100644 --- a/libs/sdk-code-schemas/package.json +++ b/libs/sdk-code-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-code-schemas", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData AAC JSON Schema types and compiled schemas", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-code-schemas/schemas/v1/src/computedAttribute.json b/libs/sdk-code-schemas/schemas/v1/src/computedAttribute.json new file mode 100644 index 00000000000..8de4ef3626c --- /dev/null +++ b/libs/sdk-code-schemas/schemas/v1/src/computedAttribute.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ComputedAttributeType", + "description": "JSON schema for Gooddata Analytics Computed Attribute", + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "computed_attribute" + } + }, + "required": ["type"] + }, + "then": { + "$ref": "#/$defs/computed_attribute" + } + } + ], + "properties": { + "type": { + "type": "string", + "enum": ["computed_attribute"] + } + }, + "required": ["type"], + "$defs": { + "computed_attribute": { + "$id": "/gaac/computed_attribute", + "title": "ComputedAttribute", + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "/gaac/identifier", + "description": "A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.", + "$semantic": [ + { + "type": "uniqueness", + "source": "computedAttribute.id", + "code": "core.uniqueness.computedAttributes.id" + }, + { + "type": "definition", + "source": "computedAttribute.id" + } + ] + }, + "type": { + "type": "string", + "enum": ["computed_attribute"] + }, + "title": { + "$ref": "/gaac/title", + "description": "An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly." + }, + "description": { + "$ref": "/gaac/description", + "description": "An optional description of the computed attribute." + }, + "tags": { + "$ref": "/gaac/tags", + "description": "A list of strings - metadata tags of this computed attribute." + }, + "maql": { + "type": "string", + "description": "Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.", + "$semantic": { + "type": "maql" + } + }, + "locale": { + "type": "string", + "description": "An optional locale whose collation order the computed values are sorted by." + } + }, + "$semantic": { + "type": "snippet", + "snippets": ["computed_attribute"] + }, + "required": ["id", "type", "maql"] + } + } +} diff --git a/libs/sdk-code-schemas/schemas/v1/src/index.json b/libs/sdk-code-schemas/schemas/v1/src/index.json index a22c456a328..88c677f9bd4 100644 --- a/libs/sdk-code-schemas/schemas/v1/src/index.json +++ b/libs/sdk-code-schemas/schemas/v1/src/index.json @@ -43,6 +43,19 @@ "$ref": "/gaac/metric" } }, + { + "if": { + "properties": { + "type": { + "const": "computed_attribute" + } + }, + "required": ["type"] + }, + "then": { + "$ref": "/gaac/computed_attribute" + } + }, { "if": { "properties": { @@ -149,6 +162,7 @@ "snippets": [ "dataset", "metric", + "computed_attribute", "date", "dashboard", "plugin", @@ -189,6 +203,7 @@ "dataset", "date", "metric", + "computed_attribute", "dashboard", "plugin", "table", diff --git a/libs/sdk-code-schemas/src/v1/metadata.json b/libs/sdk-code-schemas/src/v1/metadata.json index 148bd9c196c..832e2fbb2ee 100644 --- a/libs/sdk-code-schemas/src/v1/metadata.json +++ b/libs/sdk-code-schemas/src/v1/metadata.json @@ -16,6 +16,10 @@ "if": { "properties": { "type": { "const": "metric" } }, "required": ["type"] }, "then": { "$ref": "#/$global/gaac/metric" } }, + { + "if": { "properties": { "type": { "const": "computed_attribute" } }, "required": ["type"] }, + "then": { "$ref": "#/$global/gaac/computed_attribute" } + }, { "if": { "properties": { "type": { "const": "dashboard" } }, "required": ["type"] }, "then": { "$ref": "#/$global/gaac/dashboard" } @@ -75,6 +79,7 @@ "snippets": [ "dataset", "metric", + "computed_attribute", "date", "dashboard", "plugin", @@ -115,6 +120,7 @@ "dataset", "date", "metric", + "computed_attribute", "dashboard", "plugin", "table", @@ -422,6 +428,49 @@ "$semantic": { "type": "snippet", "snippets": ["metric"] }, "required": ["id", "type", "maql"] }, + "computed_attribute": { + "title": "ComputedAttribute", + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$global/gaac/identifier", + "description": "A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.", + "$semantic": [ + { + "type": "uniqueness", + "source": "computedAttribute.id", + "code": "core.uniqueness.computedAttributes.id" + }, + { "type": "definition", "source": "computedAttribute.id" } + ] + }, + "type": { "type": "string", "enum": ["computed_attribute"] }, + "title": { + "$ref": "#/$global/gaac/title", + "description": "An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly." + }, + "description": { + "$ref": "#/$global/gaac/description", + "description": "An optional description of the computed attribute." + }, + "tags": { + "$ref": "#/$global/gaac/tags", + "description": "A list of strings - metadata tags of this computed attribute." + }, + "maql": { + "type": "string", + "description": "Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.", + "$semantic": { "type": "maql" } + }, + "locale": { + "type": "string", + "description": "An optional locale whose collation order the computed values are sorted by." + } + }, + "$semantic": { "type": "snippet", "snippets": ["computed_attribute"] }, + "required": ["id", "type", "maql"] + }, "dashboard": { "title": "Dashboard", "type": "object", @@ -4754,6 +4803,49 @@ "mode": "property" } }, + "computed_attribute": { + "title": "ComputedAttribute", + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "$ref": "#/$global/gaac/identifier", + "description": "A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label.", + "$semantic": [ + { + "type": "uniqueness", + "source": "computedAttribute.id", + "code": "core.uniqueness.computedAttributes.id" + }, + { "type": "definition", "source": "computedAttribute.id" } + ] + }, + "type": { "type": "string", "enum": ["computed_attribute"] }, + "title": { + "$ref": "#/$global/gaac/title", + "description": "An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly." + }, + "description": { + "$ref": "#/$global/gaac/description", + "description": "An optional description of the computed attribute." + }, + "tags": { + "$ref": "#/$global/gaac/tags", + "description": "A list of strings - metadata tags of this computed attribute." + }, + "maql": { + "type": "string", + "description": "Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins.", + "$semantic": { "type": "maql" } + }, + "locale": { + "type": "string", + "description": "An optional locale whose collation order the computed values are sorted by." + } + }, + "$semantic": { "type": "snippet", "snippets": ["computed_attribute"] }, + "required": ["id", "type", "maql"] + }, "widthItem": { "title": "Width", "type": "object", diff --git a/libs/sdk-code-schemas/src/v1/metadata.ts b/libs/sdk-code-schemas/src/v1/metadata.ts index b68797384d4..b1d4f7cdc84 100644 --- a/libs/sdk-code-schemas/src/v1/metadata.ts +++ b/libs/sdk-code-schemas/src/v1/metadata.ts @@ -20,7 +20,8 @@ export type Metadata2 = | Metadata18 | Metadata21 | Metadata24 - | Metadata27; + | Metadata27 + | Metadata30; /** * JSON schema for Gooddata Analytics */ @@ -116,25 +117,38 @@ export type Tags8 = string[]; * JSON schema for Gooddata Analytics */ export type Metadata12 = Metadata13 & Metadata14; -export type Metadata14 = Dashboard; +export type Metadata14 = ComputedAttribute; /** - * A unique identifier of the dashboard. + * A unique identifier of the computed attribute. Must not collide with the identifier of an attribute or a label. */ export type Id8 = string; /** - * A list of strings - metadata tags of this dashboard. + * A list of strings - metadata tags of this computed attribute. */ export type Tags9 = string[]; +/** + * JSON schema for Gooddata Analytics + */ +export type Metadata15 = Metadata16 & Metadata17; +export type Metadata17 = Dashboard; +/** + * A unique identifier of the dashboard. + */ +export type Id9 = string; +/** + * A list of strings - metadata tags of this dashboard. + */ +export type Tags10 = string[]; export type Widget = Widget1 | Widget2 | Widget3 | Widget4; export type Widget1 = VisualisationWidget; /** * A unique identifier of the widget. */ -export type Id9 = string; +export type Id10 = string; /** * An id of the date dataset to be used for date filtering in this widget */ -export type Id10 = string; +export type Id11 = string; /** * An interaction for current widget. */ @@ -247,17 +261,17 @@ export type Widget2 = RichTextWidget; /** * A unique identifier of the widget. */ -export type Id11 = string; +export type Id12 = string; export type Widget3 = VisualizationSwitcherWidget; /** * A unique identifier of the widget. */ -export type Id12 = string; +export type Id13 = string; export type Widget4 = ContainerWidget; /** * A unique identifier of the widget. */ -export type Id13 = string; +export type Id14 = string; /** * A dashboard attribute filter */ @@ -405,41 +419,41 @@ export type DisplayAsLabelIdentifier3 = string; /** * An unique identifier of the plugin. */ -export type Id14 = string; +export type Id15 = string; /** * An unique identifier of the plugin. */ -export type Id15 = string; +export type Id16 = string; /** * A unique identifier of the tab. */ -export type Id16 = string; +export type Id17 = string; /** * JSON schema for Gooddata Analytics */ -export type Metadata15 = Metadata16 & Metadata17; -export type Metadata17 = Plugin; +export type Metadata18 = Metadata19 & Metadata20; +export type Metadata20 = Plugin; /** * A unique identifier of the plugin. */ -export type Id17 = string; +export type Id18 = string; /** * A list of strings - metadata tags of this plugin. */ -export type Tags10 = string[]; +export type Tags11 = string[]; /** * JSON schema for Gooddata Analytics */ -export type Metadata18 = Metadata19 & Metadata20; -export type Metadata20 = AttributeHierarchy; +export type Metadata21 = Metadata22 & Metadata23; +export type Metadata23 = AttributeHierarchy; /** * A unique identifier of the attribute hierarchy. */ -export type Id18 = string; +export type Id19 = string; /** * A list of strings - metadata tags of this attribute hierarchy. */ -export type Tags11 = string[]; +export type Tags12 = string[]; /** * A attribute identifier in the form of attribute/\{id\}. */ @@ -447,16 +461,16 @@ export type AttributeIdentifier6 = string; /** * JSON schema for Gooddata Analytics */ -export type Metadata21 = Metadata22 & Metadata23; -export type Metadata23 = Parameter; +export type Metadata24 = Metadata25 & Metadata26; +export type Metadata26 = Parameter; /** * A unique identifier of the parameter. */ -export type Id19 = string; +export type Id20 = string; /** * A list of strings - metadata tags of this parameter. */ -export type Tags12 = string[]; +export type Tags13 = string[]; /** * The typed definition of the parameter - its data type, default value and constraints. */ @@ -468,8 +482,8 @@ export type ParameterDefinition1 = StringParameterDefinition; /** * JSON schema for Gooddata Analytics */ -export type Metadata24 = Metadata25 & Metadata26; -export type Metadata26 = Visualisation; +export type Metadata27 = Metadata28 & Metadata29; +export type Metadata29 = Visualisation; /** * JSON schema for Gooddata Analytics Visualisation */ @@ -504,11 +518,11 @@ export type Visualisation1 = Table; /** * A unique identifier of the visualisation. */ -export type Id20 = string; +export type Id21 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags13 = string[]; +export type Tags14 = string[]; /** * This interface was referenced by `Fields3`'s JSON-Schema definition * via the `patternProperty` "^(?!\.)[.A-Za-z0-9_-]\{1,255\}$". @@ -798,18 +812,6 @@ export type SimpleBucket = string; * JSON schema for Gooddata Analytics Visualisation */ export type Visualisation2 = BarChart; -/** - * A unique identifier of the visualisation. - */ -export type Id21 = string; -/** - * A list of strings - metadata tags of this visualisation. - */ -export type Tags14 = string[]; -/** - * JSON schema for Gooddata Analytics Visualisation - */ -export type Visualisation3 = ColumnChart; /** * A unique identifier of the visualisation. */ @@ -821,7 +823,7 @@ export type Tags15 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation4 = LineChart; +export type Visualisation3 = ColumnChart; /** * A unique identifier of the visualisation. */ @@ -833,7 +835,7 @@ export type Tags16 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation5 = AreaChart; +export type Visualisation4 = LineChart; /** * A unique identifier of the visualisation. */ @@ -845,7 +847,7 @@ export type Tags17 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation6 = ScatterChart; +export type Visualisation5 = AreaChart; /** * A unique identifier of the visualisation. */ @@ -854,11 +856,10 @@ export type Id25 = string; * A list of strings - metadata tags of this visualisation. */ export type Tags18 = string[]; -export type EmptyBucket = null; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation7 = BubbleChart; +export type Visualisation6 = ScatterChart; /** * A unique identifier of the visualisation. */ @@ -867,10 +868,11 @@ export type Id26 = string; * A list of strings - metadata tags of this visualisation. */ export type Tags19 = string[]; +export type EmptyBucket = null; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation8 = PieChart; +export type Visualisation7 = BubbleChart; /** * A unique identifier of the visualisation. */ @@ -882,7 +884,7 @@ export type Tags20 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation9 = PieChart1; +export type Visualisation8 = PieChart; /** * A unique identifier of the visualisation. */ @@ -894,7 +896,7 @@ export type Tags21 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation10 = TreemapChart; +export type Visualisation9 = PieChart1; /** * A unique identifier of the visualisation. */ @@ -906,7 +908,7 @@ export type Tags22 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation11 = PyramidChart; +export type Visualisation10 = TreemapChart; /** * A unique identifier of the visualisation. */ @@ -918,7 +920,7 @@ export type Tags23 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation12 = FunnelChart; +export type Visualisation11 = PyramidChart; /** * A unique identifier of the visualisation. */ @@ -930,7 +932,7 @@ export type Tags24 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation13 = HeatmapChart; +export type Visualisation12 = FunnelChart; /** * A unique identifier of the visualisation. */ @@ -942,7 +944,7 @@ export type Tags25 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation14 = BulletChart; +export type Visualisation13 = HeatmapChart; /** * A unique identifier of the visualisation. */ @@ -954,7 +956,7 @@ export type Tags26 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation15 = WaterfallChart; +export type Visualisation14 = BulletChart; /** * A unique identifier of the visualisation. */ @@ -966,7 +968,7 @@ export type Tags27 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ -export type Visualisation16 = DependencyWheelChart; +export type Visualisation15 = WaterfallChart; /** * A unique identifier of the visualisation. */ @@ -975,6 +977,18 @@ export type Id35 = string; * A list of strings - metadata tags of this visualisation. */ export type Tags28 = string[]; +/** + * JSON schema for Gooddata Analytics Visualisation + */ +export type Visualisation16 = DependencyWheelChart; +/** + * A unique identifier of the visualisation. + */ +export type Id36 = string; +/** + * A list of strings - metadata tags of this visualisation. + */ +export type Tags29 = string[]; /** * A from attribute in this visualisation. */ @@ -990,11 +1004,11 @@ export type Visualisation17 = SankeyChart; /** * A unique identifier of the visualisation. */ -export type Id36 = string; +export type Id37 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags29 = string[]; +export type Tags30 = string[]; /** * A from attribute in this visualisation. */ @@ -1010,11 +1024,11 @@ export type Visualisation18 = HeadlineChart; /** * A unique identifier of the visualisation. */ -export type Id37 = string; +export type Id38 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags30 = string[]; +export type Tags31 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ @@ -1022,11 +1036,11 @@ export type Visualisation19 = ComboChart; /** * A unique identifier of the visualisation. */ -export type Id38 = string; +export type Id39 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags31 = string[]; +export type Tags32 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ @@ -1034,11 +1048,11 @@ export type Visualisation20 = GeoChart; /** * A unique identifier of the visualisation. */ -export type Id39 = string; +export type Id40 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags32 = string[]; +export type Tags33 = string[]; export type PushpinLocationBucket = string; export type LayerItem = | VisualizationDataLayer @@ -1063,7 +1077,7 @@ export type LayerItem = /** * A unique identifier of the visualization data layer. */ -export type Id40 = string; +export type Id41 = string; export type LocationBucket = string; export type GeoAreaBucket = string; /** @@ -1073,11 +1087,11 @@ export type Visualisation21 = GeoAreaChart; /** * A unique identifier of the visualisation. */ -export type Id41 = string; +export type Id42 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags33 = string[]; +export type Tags34 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ @@ -1085,11 +1099,11 @@ export type Visualisation22 = RepeaterChart; /** * A unique identifier of the visualisation. */ -export type Id42 = string; +export type Id43 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags34 = string[]; +export type Tags35 = string[]; /** * JSON schema for Gooddata Analytics Visualisation */ @@ -1097,16 +1111,16 @@ export type Visualisation23 = RadarChart; /** * A unique identifier of the visualisation. */ -export type Id43 = string; +export type Id44 = string; /** * A list of strings - metadata tags of this visualisation. */ -export type Tags35 = string[]; +export type Tags36 = string[]; /** * JSON schema for Gooddata Analytics */ -export type Metadata27 = Metadata28 & Metadata29; -export type Metadata29 = { +export type Metadata30 = Metadata31 & Metadata32; +export type Metadata32 = { [k: string]: unknown; }; @@ -1115,6 +1129,7 @@ export interface Metadata1 { | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -1149,6 +1164,7 @@ export interface Metadata4 { | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -1611,6 +1627,7 @@ export interface Metadata7 { | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -1697,6 +1714,7 @@ export interface Metadata10 { | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -1761,6 +1779,7 @@ export interface Metadata13 { | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -1790,8 +1809,64 @@ export interface Metadata13 { | "parameter"; [k: string]: unknown; } -export interface Dashboard { +export interface ComputedAttribute { id: Id8; + type: "computed_attribute"; + /** + * An optional human readable title for the computed attribute. Will be derived from id if not provided explicitly. + */ + title?: string; + /** + * An optional description of the computed attribute. + */ + description?: string; + tags?: Tags9; + /** + * Define MAQL syntax for the computed attribute. Values are assigned with break points written as CASE WHEN branches over a metric, and the first matching branch wins. + */ + maql: string; + /** + * An optional locale whose collation order the computed values are sorted by. + */ + locale?: string; +} +export interface Metadata16 { + type: + | "dataset" + | "date" + | "metric" + | "computed_attribute" + | "dashboard" + | "plugin" + | "table" + | "bar_chart" + | "column_chart" + | "line_chart" + | "area_chart" + | "scatter_chart" + | "bubble_chart" + | "pie_chart" + | "donut_chart" + | "treemap_chart" + | "pyramid_chart" + | "funnel_chart" + | "heatmap_chart" + | "bullet_chart" + | "waterfall_chart" + | "dependency_wheel_chart" + | "sankey_chart" + | "headline_chart" + | "combo_chart" + | "geo_chart" + | "geo_area_chart" + | "repeater_chart" + | "radar_chart" + | "attribute_hierarchy" + | "parameter"; + [k: string]: unknown; +} +export interface Dashboard { + id: Id9; type: "dashboard"; /** * Dashboard model version. "2" (default if omitted) — legacy shape: root-level sections/filters are also mirrored into a default tab, producing a declarative model with duplicated content for backward compatibility with older SDK readers. "3" — clean shape: tabs are the sole source of layout and filters; root sections/filters in YAML are still allowed as an authoring shortcut but are wrapped into a single synthetic tab without duplication. Use "3" for new dashboards; "2" exists to keep existing files round-trippable. @@ -1805,7 +1880,7 @@ export interface Dashboard { * An optional description of the dashboard. */ description?: string; - tags?: Tags9; + tags?: Tags10; /** * Whether cross filtering is enabled for this dashboard. Defaults to true. */ @@ -1841,7 +1916,7 @@ export interface Dashboard { */ plugins?: ( | { - id: Id14; + id: Id15; /** * Parameter that will be passed to the plugin. Everything other than string will be serialized to JSON automatically. */ @@ -1849,7 +1924,7 @@ export interface Dashboard { [k: string]: unknown; }; } - | Id15 + | Id16 )[]; /** * A list of tabs in this dashboard. Each tab has its own layout, filters, and filter configurations. Mutually exclusive with sections and filters at dashboard level. @@ -1896,7 +1971,7 @@ export interface Section { widgets: Widget[]; } export interface VisualisationWidget { - id?: Id9; + id?: Id10; /** * An id of the visualization to be rendered with the widget */ @@ -1911,7 +1986,7 @@ export interface VisualisationWidget { * An optional height of the widget in the grid, each row being ~20px high */ rows?: number; - date?: Id10; + date?: Id11; /** * A list of dashboard filters to be ignored for this widget */ @@ -2008,7 +2083,7 @@ export interface IgnoredDrillDownIntersection { [k: string]: unknown; } export interface RichTextWidget { - id?: Id11; + id?: Id12; /** * A markdown content of the widget */ @@ -2023,7 +2098,7 @@ export interface RichTextWidget { rows?: number; } export interface VisualizationSwitcherWidget { - id?: Id12; + id?: Id13; /** * An optional width of the widget in the grid, total width being 12 columns */ @@ -2038,7 +2113,7 @@ export interface VisualizationSwitcherWidget { visualizations: VisualisationWidget1[]; } export interface VisualisationWidget1 { - id?: Id9; + id?: Id10; /** * An id of the visualization to be rendered with the widget */ @@ -2053,7 +2128,7 @@ export interface VisualisationWidget1 { * An optional height of the widget in the grid, each row being ~20px high */ rows?: number; - date?: Id10; + date?: Id11; /** * A list of dashboard filters to be ignored for this widget */ @@ -2077,7 +2152,7 @@ export interface VisualisationWidget1 { ignored_cross_filtering?: boolean; } export interface ContainerWidget { - container: Id13; + container: Id14; /** * An optional width of the widget within the grid. When the parent container's direction is set to 'row', widget widths can vary up to the width of the container. Widgets are placed next to each other and wrap to the next row when their combined width exceeds that of the container. When the direction is set to 'column', the width does not need to be set, or it should match the width of the container. */ @@ -2268,7 +2343,7 @@ export interface DashboardFilterGroup { type: "date_filter" | "attribute_filter" | "text_filter" | "metric_value_filter" | "filter_group"; } export interface Tab { - id: Id16; + id: Id17; /** * Display title for the tab. */ @@ -2306,11 +2381,12 @@ export interface Permission { user_groups?: string[]; [k: string]: unknown; } -export interface Metadata16 { +export interface Metadata19 { type: | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -2341,7 +2417,7 @@ export interface Metadata16 { [k: string]: unknown; } export interface Plugin { - id: Id17; + id: Id18; type: "plugin"; /** * An optional human readable title for the plugin. Will be derived from id if not provided explicitly. @@ -2351,17 +2427,18 @@ export interface Plugin { * An optional description of the plugin. */ description?: string; - tags?: Tags10; + tags?: Tags11; /** * URL of the plugin. */ url: string; } -export interface Metadata19 { +export interface Metadata22 { type: | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -2392,7 +2469,7 @@ export interface Metadata19 { [k: string]: unknown; } export interface AttributeHierarchy { - id: Id18; + id: Id19; type: "attribute_hierarchy"; /** * An optional human readable title for the attribute hierarchy. Will be derived from id if not provided explicitly. @@ -2402,17 +2479,18 @@ export interface AttributeHierarchy { * An optional description of the attribute hierarchy. */ description?: string; - tags?: Tags11; + tags?: Tags12; /** * A list of sorted attributes use in attribute hierarchy. The first attribute is the top level attribute. */ attributes: [AttributeIdentifier6, ...AttributeIdentifier6[]]; } -export interface Metadata22 { +export interface Metadata25 { type: | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -2443,7 +2521,7 @@ export interface Metadata22 { [k: string]: unknown; } export interface Parameter { - id: Id19; + id: Id20; type: "parameter"; /** * An optional human readable title for the parameter. Will be derived from id if not provided explicitly. @@ -2453,7 +2531,7 @@ export interface Parameter { * An optional description of the parameter. */ description?: string; - tags?: Tags12; + tags?: Tags13; definition: ParameterDefinition; } /** @@ -2494,11 +2572,12 @@ export interface ParameterAllowedValue { */ title?: string; } -export interface Metadata25 { +export interface Metadata28 { type: | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" @@ -2533,7 +2612,7 @@ export interface Table { * Type of visualisation. */ type: "table"; - id: Id20; + id: Id21; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -2542,7 +2621,7 @@ export interface Table { * An optional description of the visualisation. */ description?: string; - tags?: Tags13; + tags?: Tags14; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -3580,7 +3659,7 @@ export interface BarChart { * Type of visualisation. */ type: "bar_chart"; - id: Id21; + id: Id22; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -3589,7 +3668,7 @@ export interface BarChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags14; + tags?: Tags15; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -3959,7 +4038,7 @@ export interface ColumnChart { * Type of visualisation. */ type: "column_chart"; - id: Id22; + id: Id23; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -3968,7 +4047,7 @@ export interface ColumnChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags15; + tags?: Tags16; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -4338,7 +4417,7 @@ export interface LineChart { * Type of visualisation. */ type: "line_chart"; - id: Id23; + id: Id24; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -4347,7 +4426,7 @@ export interface LineChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags16; + tags?: Tags17; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -4717,7 +4796,7 @@ export interface AreaChart { * Type of visualisation. */ type: "area_chart"; - id: Id24; + id: Id25; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -4726,7 +4805,7 @@ export interface AreaChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags17; + tags?: Tags18; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -5096,7 +5175,7 @@ export interface ScatterChart { * Type of visualisation. */ type: "scatter_chart"; - id: Id25; + id: Id26; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -5105,7 +5184,7 @@ export interface ScatterChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags18; + tags?: Tags19; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -5475,7 +5554,7 @@ export interface BubbleChart { * Type of visualisation. */ type: "bubble_chart"; - id: Id26; + id: Id27; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -5484,7 +5563,7 @@ export interface BubbleChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags19; + tags?: Tags20; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -5854,7 +5933,7 @@ export interface PieChart { * Type of visualisation. */ type: "pie_chart"; - id: Id27; + id: Id28; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -5863,7 +5942,7 @@ export interface PieChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags20; + tags?: Tags21; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -6229,7 +6308,7 @@ export interface PieChart1 { * Type of visualisation. */ type: "donut_chart"; - id: Id28; + id: Id29; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -6238,7 +6317,7 @@ export interface PieChart1 { * An optional description of the visualisation. */ description?: string; - tags?: Tags21; + tags?: Tags22; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -6604,7 +6683,7 @@ export interface TreemapChart { * Type of visualisation. */ type: "treemap_chart"; - id: Id29; + id: Id30; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -6613,7 +6692,7 @@ export interface TreemapChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags22; + tags?: Tags23; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -6979,7 +7058,7 @@ export interface PyramidChart { * Type of visualisation. */ type: "pyramid_chart"; - id: Id30; + id: Id31; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -6988,7 +7067,7 @@ export interface PyramidChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags23; + tags?: Tags24; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -7354,7 +7433,7 @@ export interface FunnelChart { * Type of visualisation. */ type: "funnel_chart"; - id: Id31; + id: Id32; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -7363,7 +7442,7 @@ export interface FunnelChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags24; + tags?: Tags25; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -7729,7 +7808,7 @@ export interface HeatmapChart { * Type of visualisation. */ type: "heatmap_chart"; - id: Id32; + id: Id33; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -7738,7 +7817,7 @@ export interface HeatmapChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags25; + tags?: Tags26; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -8112,7 +8191,7 @@ export interface BulletChart { * Type of visualisation. */ type: "bullet_chart"; - id: Id33; + id: Id34; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -8121,7 +8200,7 @@ export interface BulletChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags26; + tags?: Tags27; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -8487,7 +8566,7 @@ export interface WaterfallChart { * Type of visualisation. */ type: "waterfall_chart"; - id: Id34; + id: Id35; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -8496,7 +8575,7 @@ export interface WaterfallChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags27; + tags?: Tags28; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -8862,7 +8941,7 @@ export interface DependencyWheelChart { * Type of visualisation. */ type: "dependency_wheel_chart"; - id: Id35; + id: Id36; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -8871,7 +8950,7 @@ export interface DependencyWheelChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags28; + tags?: Tags29; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -9239,7 +9318,7 @@ export interface SankeyChart { * Type of visualisation. */ type: "sankey_chart"; - id: Id36; + id: Id37; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -9248,7 +9327,7 @@ export interface SankeyChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags29; + tags?: Tags30; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -9616,7 +9695,7 @@ export interface HeadlineChart { * Type of visualisation. */ type: "headline_chart"; - id: Id37; + id: Id38; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -9625,7 +9704,7 @@ export interface HeadlineChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags30; + tags?: Tags31; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -9991,7 +10070,7 @@ export interface ComboChart { * Type of visualisation. */ type: "combo_chart"; - id: Id38; + id: Id39; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -10000,7 +10079,7 @@ export interface ComboChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags31; + tags?: Tags32; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -10366,7 +10445,7 @@ export interface GeoChart { * Type of visualisation. */ type: "geo_chart"; - id: Id39; + id: Id40; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -10375,7 +10454,7 @@ export interface GeoChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags32; + tags?: Tags33; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -10741,7 +10820,7 @@ export interface VisualisationConfig19 { [k: string]: unknown; } export interface VisualizationDataLayer { - id: Id40; + id: Id41; /** * An optional human readable title for the layer. Will be derived from id if not provided explicitly. */ @@ -11097,7 +11176,7 @@ export interface GeoAreaChart { * Type of visualisation. */ type: "geo_area_chart"; - id: Id41; + id: Id42; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -11106,7 +11185,7 @@ export interface GeoAreaChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags33; + tags?: Tags34; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -11476,7 +11555,7 @@ export interface RepeaterChart { * Type of visualisation. */ type: "repeater_chart"; - id: Id42; + id: Id43; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -11485,7 +11564,7 @@ export interface RepeaterChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags34; + tags?: Tags35; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -11859,7 +11938,7 @@ export interface RadarChart { * Type of visualisation. */ type: "radar_chart"; - id: Id43; + id: Id44; /** * An optional human readable title for the visualisation. Will be derived from id if not provided explicitly. */ @@ -11868,7 +11947,7 @@ export interface RadarChart { * An optional description of the visualisation. */ description?: string; - tags?: Tags35; + tags?: Tags36; /** * Optional flag to indicate if the visualisation should be shown in AI results. When omitted, the visualisation is visible. */ @@ -12229,11 +12308,12 @@ export interface VisualisationConfig23 { }; [k: string]: unknown; } -export interface Metadata28 { +export interface Metadata31 { type: | "dataset" | "date" | "metric" + | "computed_attribute" | "dashboard" | "plugin" | "table" diff --git a/libs/sdk-e2e-utils/package.json b/libs/sdk-e2e-utils/package.json index a02e0cb8800..6baa197d414 100644 --- a/libs/sdk-e2e-utils/package.json +++ b/libs/sdk-e2e-utils/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-e2e-utils", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData utility functions for Playwright E2E tests", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-embedding/package.json b/libs/sdk-embedding/package.json index 0d4d64f5281..f58929adf7a 100644 --- a/libs/sdk-embedding/package.json +++ b/libs/sdk-embedding/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-embedding", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData Embedding APIs", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-model/api/sdk-model.api.md b/libs/sdk-model/api/sdk-model.api.md index b188981785a..938372e96a2 100644 --- a/libs/sdk-model/api/sdk-model.api.md +++ b/libs/sdk-model/api/sdk-model.api.md @@ -340,13 +340,13 @@ export type CalendarContext = { export type CalendarType = "STANDARD" | "FISCAL"; // @public -export type CatalogItem = ICatalogAttribute | ICatalogMeasure | ICatalogFact | ICatalogDateDataset | ICatalogAttributeHierarchy; +export type CatalogItem = ICatalogAttribute | ICatalogMeasure | ICatalogFact | ICatalogDateDataset | ICatalogAttributeHierarchy | ICatalogComputedAttribute; // @public export const catalogItemMetadataObject: (catalogItem: CatalogItem) => MetadataObject; // @public -export type CatalogItemType = "attribute" | "measure" | "fact" | "dateDataset" | "attributeHierarchy"; +export type CatalogItemType = "attribute" | "measure" | "fact" | "dateDataset" | "attributeHierarchy" | "computedAttribute"; // @internal export type CertificationStatus = "CERTIFIED"; @@ -363,6 +363,9 @@ export type ComparatorDirection = "asc" | "desc"; // @public (undocumented) export type ComparisonConditionOperator = "GREATER_THAN" | "GREATER_THAN_OR_EQUAL_TO" | "LESS_THAN" | "LESS_THAN_OR_EQUAL_TO" | "EQUAL_TO" | "NOT_EQUAL_TO"; +// @public +export type ComputedAttributeDataType = "INT" | "STRING" | "DATE" | "NUMERIC" | "TIMESTAMP" | "TIMESTAMP_TZ" | "BOOLEAN" | "HLL"; + // @public export enum ComputeRatioRule { ANY_MEASURE = 2, @@ -433,7 +436,7 @@ export const CSV_DELIMITER_PRESETS: { }; // @alpha -export type CsvDelimiterPreset = CsvDelimiterPresetId | "custom"; +export type CsvDelimiterPreset = CsvDelimiterPresetId | "custom" | "inherit"; // @alpha export type CsvDelimiterPresetId = keyof typeof CSV_DELIMITER_PRESETS; @@ -582,6 +585,9 @@ export const DateGranularity: { // @beta export type DateString = string; +// @alpha +export const DEFAULT_ABSOLUTE_DATE_FILTER_GRANULARITIES: DateFilterGranularity[]; + // @alpha export const DEFAULT_CSV_DELIMITER: ","; @@ -903,7 +909,7 @@ export function getCsvDelimiterState(delimiter?: string): { export function getCsvDelimiterValidationError(delimiter: string): CsvDelimiterValidationError | undefined; // @alpha -export function getCsvDelimiterValue(selectedPreset: CsvDelimiterPreset, customDelimiter: string): string; +export function getCsvDelimiterValue(selectedPreset: CsvDelimiterPreset, customDelimiter: string): string | undefined; // @alpha export const getDateFilterGranularities: (query: IGranularitiesQuery) => DateFilterGranularity[]; @@ -954,7 +960,7 @@ export const GRANULARITY_DESCRIPTORS: Record string; @@ -6941,7 +6991,7 @@ export type ObjectOrigin = "ALL" | "PARENTS" | "NATIVE"; export type ObjectPermissionsObjectKind = "attribute" | "fact" | "label" | "measure"; // @public -export type ObjectType = "measure" | "fact" | "attribute" | "displayForm" | "dataSet" | "tag" | "insight" | "variable" | "analyticalDashboard" | "theme" | "colorPalette" | "workspaceTheme" | "workspaceColorPalette" | "filterContext" | "dashboardPlugin" | "attributeHierarchy" | "user" | "userGroup" | "dateHierarchyTemplate" | "dateAttributeHierarchy" | "exportDefinition" | "automation" | "filterView" | "workspaceDataFilter" | "workspaceDataFilterSetting" | "userDataFilter" | "notificationChannel" | "memoryItem" | "parameter"; +export type ObjectType = "measure" | "fact" | "attribute" | "computedAttribute" | "displayForm" | "dataSet" | "tag" | "insight" | "variable" | "analyticalDashboard" | "theme" | "colorPalette" | "workspaceTheme" | "workspaceColorPalette" | "filterContext" | "dashboardPlugin" | "attributeHierarchy" | "user" | "userGroup" | "dateHierarchyTemplate" | "dateAttributeHierarchy" | "exportDefinition" | "automation" | "filterView" | "workspaceDataFilter" | "workspaceDataFilterSetting" | "userDataFilter" | "notificationChannel" | "memoryItem" | "parameter"; // @public export type ObjRef = UriRef | IdentifierRef; diff --git a/libs/sdk-model/package.json b/libs/sdk-model/package.json index 72700af80eb..6067a82ac4c 100644 --- a/libs/sdk-model/package.json +++ b/libs/sdk-model/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-model", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData Model definitions used by UI components and Backend SPI", "license": "MIT", "author": "GoodData", diff --git a/libs/sdk-model/src/dashboard/alerts.fixtures.ts b/libs/sdk-model/src/dashboard/alerts.test.helpers.ts similarity index 93% rename from libs/sdk-model/src/dashboard/alerts.fixtures.ts rename to libs/sdk-model/src/dashboard/alerts.test.helpers.ts index abf89e9b985..b10b3ffdcce 100644 --- a/libs/sdk-model/src/dashboard/alerts.fixtures.ts +++ b/libs/sdk-model/src/dashboard/alerts.test.helpers.ts @@ -3,7 +3,7 @@ import { uriRef } from "../objRef/factory.js"; import { type IWidgetAlert, type IWidgetAlertDefinition } from "./alert.js"; -import { filterContextDefinition } from "./filterContext.fixtures.js"; +import { filterContextDefinition } from "./filterContext.test.helpers.js"; export const widgetAlert: IWidgetAlert = { dashboard: uriRef("/dashboard"), diff --git a/libs/sdk-model/src/dashboard/alerts.test.ts b/libs/sdk-model/src/dashboard/alerts.test.ts index 55dabd313fb..5fde7d843e1 100644 --- a/libs/sdk-model/src/dashboard/alerts.test.ts +++ b/libs/sdk-model/src/dashboard/alerts.test.ts @@ -9,7 +9,7 @@ import { widgetAlert, widgetAlertDefinitionToCreate, widgetAlertDefinitionToUpdate, -} from "./alerts.fixtures.js"; +} from "./alerts.test.helpers.js"; describe("dashboard widget alerts type guards", () => { describe("isWidgetAlert", () => { diff --git a/libs/sdk-model/src/dashboard/dashboard.ts b/libs/sdk-model/src/dashboard/dashboard.ts index 73cba4b5c31..7020d638c9e 100644 --- a/libs/sdk-model/src/dashboard/dashboard.ts +++ b/libs/sdk-model/src/dashboard/dashboard.ts @@ -348,19 +348,39 @@ export function resolveTimezoneId(timezoneId: DashboardTimezoneId | undefined): : timezoneId; } +/** + * Signed offset-style identifiers (`±HH`, `±HHMM`, `±HH:MM`, optionally with seconds). + * Some `Intl` implementations accept these as `timeZone` values, but they are not named + * IANA timezone IDs. Named IDs such as `"Etc/GMT+1"` do not match this pattern. + */ +const OFFSET_STYLE_TIMEZONE_ID = /^[+-]\d{2}(?:\d{2}|:\d{2}(?::\d{2}(?:\.\d+)?)?)?$/; + /** * Tests whether `timezoneId` is a valid IANA timezone identifier according to * the runtime ICU data (via `Intl.DateTimeFormat`). The {@link BROWSER_DETECTED} * sentinel is not a valid IANA ID — use {@link isValidDashboardTimezoneId} for * values stored on the dashboard. * + * Identifiers are case-sensitive. `Intl` accepts timezones case-insensitively, so + * a value that only differs in case from the canonical form (e.g. `"america/new_york"`) + * is rejected. Aliases that resolve to a different identifier (e.g. `"Etc/UTC"` → `"UTC"`) + * are still accepted as ICU-known IDs. Offset-style identifiers (e.g. `"+01"`, `"+0100"`, + * `"+01:00"`) are rejected. + * * @param timezoneId - timezone identifier to test * @alpha */ export function isValidIanaTimezoneId(timezoneId: string): boolean { + if (OFFSET_STYLE_TIMEZONE_ID.test(timezoneId)) { + return false; + } try { - new Intl.DateTimeFormat(undefined, { timeZone: timezoneId }); - return true; + const canonical = new Intl.DateTimeFormat(undefined, { timeZone: timezoneId }).resolvedOptions() + .timeZone; + // Intl accepts IDs case-insensitively; IANA identifiers are case-sensitive. + // Reject values that only differ in case from the canonical form. Aliases + // that resolve to a different identifier still pass. + return canonical === timezoneId || canonical.toLowerCase() !== timezoneId.toLowerCase(); } catch { return false; } diff --git a/libs/sdk-model/src/dashboard/drills.fixtures.ts b/libs/sdk-model/src/dashboard/drills.test.helpers.ts similarity index 100% rename from libs/sdk-model/src/dashboard/drills.fixtures.ts rename to libs/sdk-model/src/dashboard/drills.test.helpers.ts diff --git a/libs/sdk-model/src/dashboard/drills.test.ts b/libs/sdk-model/src/dashboard/drills.test.ts index a7fb457be3f..6336ba2a201 100644 --- a/libs/sdk-model/src/dashboard/drills.test.ts +++ b/libs/sdk-model/src/dashboard/drills.test.ts @@ -17,7 +17,7 @@ import { drillToDashboard, drillToInsight, drillToLegacyDashboard, -} from "./drills.fixtures.js"; +} from "./drills.test.helpers.js"; describe("dashboard drills type guards", () => { describe("isDrillToLegacyDashboard", () => { diff --git a/libs/sdk-model/src/dashboard/filterContext.fixtures.ts b/libs/sdk-model/src/dashboard/filterContext.test.helpers.ts similarity index 100% rename from libs/sdk-model/src/dashboard/filterContext.fixtures.ts rename to libs/sdk-model/src/dashboard/filterContext.test.helpers.ts diff --git a/libs/sdk-model/src/dashboard/filterContext.test.ts b/libs/sdk-model/src/dashboard/filterContext.test.ts index a2003ad4cae..1cc9ba8029d 100644 --- a/libs/sdk-model/src/dashboard/filterContext.test.ts +++ b/libs/sdk-model/src/dashboard/filterContext.test.ts @@ -5,15 +5,6 @@ import { describe, expect, it } from "vitest"; import { InvalidInputTestCases } from "../../__mocks__/typeGuards.js"; import { type ObjRef } from "../objRef/index.js"; -import { - dashboardAttributeFilter, - dashboardAttributeFilterReference, - dashboardDateFilter, - dashboardDateFilterReference, - filterContext, - filterContextDefinition, - tempFilterContext, -} from "./filterContext.fixtures.js"; import { type IDashboardFilterReference, type IFilterContext, @@ -29,6 +20,15 @@ import { isFilterContextDefinition, isTempFilterContext, } from "./filterContext.js"; +import { + dashboardAttributeFilter, + dashboardAttributeFilterReference, + dashboardDateFilter, + dashboardDateFilterReference, + filterContext, + filterContextDefinition, + tempFilterContext, +} from "./filterContext.test.helpers.js"; describe("filter context type guards", () => { describe("isDashboardAttributeFilter", () => { diff --git a/libs/sdk-model/src/dashboard/kpi.fixtures.ts b/libs/sdk-model/src/dashboard/kpi.test.helpers.ts similarity index 100% rename from libs/sdk-model/src/dashboard/kpi.fixtures.ts rename to libs/sdk-model/src/dashboard/kpi.test.helpers.ts diff --git a/libs/sdk-model/src/dashboard/kpi.test.ts b/libs/sdk-model/src/dashboard/kpi.test.ts index 10f2fba3a38..fdbc1eee8fd 100644 --- a/libs/sdk-model/src/dashboard/kpi.test.ts +++ b/libs/sdk-model/src/dashboard/kpi.test.ts @@ -4,8 +4,8 @@ import { describe, expect, it } from "vitest"; import { InvalidInputTestCases } from "../../__mocks__/typeGuards.js"; -import { kpiWithComparison, kpiWithoutComparison } from "./kpi.fixtures.js"; import { isKpiWithComparison, isKpiWithoutComparison } from "./kpi.js"; +import { kpiWithComparison, kpiWithoutComparison } from "./kpi.test.helpers.js"; describe("kpi type guards", () => { describe("isKpiWithComparison", () => { diff --git a/libs/sdk-model/src/dashboard/parameter.fixtures.ts b/libs/sdk-model/src/dashboard/parameter.test.helpers.ts similarity index 100% rename from libs/sdk-model/src/dashboard/parameter.fixtures.ts rename to libs/sdk-model/src/dashboard/parameter.test.helpers.ts diff --git a/libs/sdk-model/src/dashboard/parameter.test.ts b/libs/sdk-model/src/dashboard/parameter.test.ts index 34a4a1b8cbd..66a35632a81 100644 --- a/libs/sdk-model/src/dashboard/parameter.test.ts +++ b/libs/sdk-model/src/dashboard/parameter.test.ts @@ -4,12 +4,12 @@ import { describe, expect, it } from "vitest"; import { InvalidInputTestCases } from "../../__mocks__/typeGuards.js"; +import { isDashboardParameter } from "./parameter.js"; import { dashboardParameterFull, dashboardParameterMinimal, dashboardParameterString, -} from "./parameter.fixtures.js"; -import { isDashboardParameter } from "./parameter.js"; +} from "./parameter.test.helpers.js"; describe("dashboard parameter type guards", () => { describe("isDashboardParameter", () => { diff --git a/libs/sdk-model/src/dashboard/timezone.test.ts b/libs/sdk-model/src/dashboard/timezone.test.ts index 995384962e2..f69c9cc5777 100644 --- a/libs/sdk-model/src/dashboard/timezone.test.ts +++ b/libs/sdk-model/src/dashboard/timezone.test.ts @@ -8,8 +8,23 @@ describe("dashboard timezone validation", () => { describe("isValidIanaTimezoneId", () => { it("accepts real IANA identifiers", () => { expect(isValidIanaTimezoneId("UTC")).toBe(true); + expect(isValidIanaTimezoneId("Etc/UTC")).toBe(true); expect(isValidIanaTimezoneId("Europe/Prague")).toBe(true); expect(isValidIanaTimezoneId("America/New_York")).toBe(true); + expect(isValidIanaTimezoneId("America/Indiana/Indianapolis")).toBe(true); + }); + + it("rejects non valid IANA identifiers ", () => { + expect(isValidIanaTimezoneId("america/new_york")).toBe(false); + expect(isValidIanaTimezoneId("Australia/eucla")).toBe(false); + }); + + it("rejects offset-style identifiers", () => { + expect(isValidIanaTimezoneId("+01")).toBe(false); + expect(isValidIanaTimezoneId("+0100")).toBe(false); + expect(isValidIanaTimezoneId("-2359")).toBe(false); + expect(isValidIanaTimezoneId("+23")).toBe(false); + expect(isValidIanaTimezoneId("+01:00")).toBe(false); }); it("rejects unknown or malformed identifiers", () => { diff --git a/libs/sdk-model/src/dashboard/widgets.fixtures.ts b/libs/sdk-model/src/dashboard/widgets.test.helpers.ts similarity index 100% rename from libs/sdk-model/src/dashboard/widgets.fixtures.ts rename to libs/sdk-model/src/dashboard/widgets.test.helpers.ts diff --git a/libs/sdk-model/src/dashboard/widgets.test.ts b/libs/sdk-model/src/dashboard/widgets.test.ts index 6aaaeec18e9..63b34e2deba 100644 --- a/libs/sdk-model/src/dashboard/widgets.test.ts +++ b/libs/sdk-model/src/dashboard/widgets.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { InvalidInputTestCases } from "../../__mocks__/typeGuards.js"; import { isWidget, isWidgetDefinition } from "./widget.js"; -import { widget, widgetDefinition } from "./widgets.fixtures.js"; +import { widget, widgetDefinition } from "./widgets.test.helpers.js"; describe("widget type guards", () => { describe("isWidget", () => { diff --git a/libs/sdk-model/src/dateFilterConfig/index.ts b/libs/sdk-model/src/dateFilterConfig/index.ts index b1450cc96dd..f0693d63044 100644 --- a/libs/sdk-model/src/dateFilterConfig/index.ts +++ b/libs/sdk-model/src/dateFilterConfig/index.ts @@ -109,6 +109,18 @@ const dateFilterGranularity: DateFilterGranularity[] = [ export const isDateFilterGranularity = (obj: unknown): obj is DateFilterGranularity => !isEmpty(obj) && dateFilterGranularity.some((granularity) => granularity === obj); +/** + * Standard-calendar granularities that an absolute (static) date filter can be configured with. + * @alpha + */ +export const DEFAULT_ABSOLUTE_DATE_FILTER_GRANULARITIES: DateFilterGranularity[] = [ + "GDC.time.date", + "GDC.time.week_us", + "GDC.time.month", + "GDC.time.quarter", + "GDC.time.year", +]; + /** * Runs {@link getGranularities} and narrows the result to the {@link DateFilterGranularity} subset. * @alpha @@ -215,6 +227,13 @@ export interface IAbsoluteDateFilterForm extends IDateFilterOption { * Type to identify the global absolute date filter */ type: DateFilterOptionAbsoluteFormType; + /** + * Available granularities for the global absolute date filter. + * + * @remarks + * When not set, the absolute date filter behaves exactly as it does today: day-level selection only. + */ + availableGranularities?: DateFilterGranularity[]; /** * Optional configuration for how this option should treat empty date values. */ diff --git a/libs/sdk-model/src/dateFilterConfig/typeGuards.fixtures.ts b/libs/sdk-model/src/dateFilterConfig/typeGuards.test.helpers.ts similarity index 80% rename from libs/sdk-model/src/dateFilterConfig/typeGuards.fixtures.ts rename to libs/sdk-model/src/dateFilterConfig/typeGuards.test.helpers.ts index 9bfc43d707b..b9b9e5a34c7 100644 --- a/libs/sdk-model/src/dateFilterConfig/typeGuards.fixtures.ts +++ b/libs/sdk-model/src/dateFilterConfig/typeGuards.test.helpers.ts @@ -23,6 +23,20 @@ export const absoluteDateFilterForm: IAbsoluteDateFilterForm = { visible: true, }; +export const absoluteDateFilterFormWithGranularities: IAbsoluteDateFilterForm = { + localIdentifier: "absoluteDateFilterForm", + name: "absoluteDateFilterForm", + type: "absoluteForm", + visible: true, + availableGranularities: [ + "GDC.time.date", + "GDC.time.week_us", + "GDC.time.month", + "GDC.time.quarter", + "GDC.time.year", + ], +}; + export const absoluteDateFilterPreset: IAbsoluteDateFilterPreset = { localIdentifier: "absoluteDateFilterForm", name: "absoluteDateFilterForm", diff --git a/libs/sdk-model/src/dateFilterConfig/typeGuards.test.ts b/libs/sdk-model/src/dateFilterConfig/typeGuards.test.ts index e8f46f44a37..b207cd958cf 100644 --- a/libs/sdk-model/src/dateFilterConfig/typeGuards.test.ts +++ b/libs/sdk-model/src/dateFilterConfig/typeGuards.test.ts @@ -14,12 +14,13 @@ import { } from "./index.js"; import { absoluteDateFilterForm, + absoluteDateFilterFormWithGranularities, absoluteDateFilterPreset, allTimeDateFilter, emptyValuesDateFilterOption, relativeDateFilterForm, relativeDateFilterPreset, -} from "./typeGuards.fixtures.js"; +} from "./typeGuards.test.helpers.js"; describe("dashboard extended date filters type guards", () => { describe("isAllTimeDateFilterOption", () => { @@ -44,6 +45,11 @@ describe("dashboard extended date filters type guards", () => { [false, "all time date filter", allTimeDateFilter], [false, "empty values date filter option", emptyValuesDateFilterOption], [true, "absolute date filter form", absoluteDateFilterForm], + [ + true, + "absolute date filter form with availableGranularities", + absoluteDateFilterFormWithGranularities, + ], [false, "absolute date filter preset", absoluteDateFilterPreset], [false, "relative date filter form", relativeDateFilterForm], [false, "relative date filter preset", relativeDateFilterPreset], diff --git a/libs/sdk-model/src/exports/csvDelimiter.ts b/libs/sdk-model/src/exports/csvDelimiter.ts index 22b27ddca46..b59eec0d081 100644 --- a/libs/sdk-model/src/exports/csvDelimiter.ts +++ b/libs/sdk-model/src/exports/csvDelimiter.ts @@ -36,11 +36,16 @@ const SUPPORTED_CSV_DELIMITER_REGEXP = /^[\t !#$%&()*+\-.,/:;<=>?@\[\]\\^_{|}~]$ export type CsvDelimiterPresetId = keyof typeof CSV_DELIMITER_PRESETS; /** - * Identifier of a CSV delimiter preset, or "custom" when the user provides their own character. + * Identifier of a CSV delimiter preset, "custom" when the user provides their own character, + * or "inherit" when no delimiter should be sent and the backend-resolved default should apply. + * + * @remarks + * "custom" and "inherit" are sentinels with no delimiter character of their own; only + * {@link CsvDelimiterPresetId} members are valid keys into {@link CSV_DELIMITER_PRESETS}. * * @alpha */ -export type CsvDelimiterPreset = CsvDelimiterPresetId | "custom"; +export type CsvDelimiterPreset = CsvDelimiterPresetId | "custom" | "inherit"; /** * Validation error codes returned by {@link getCsvDelimiterValidationError}. @@ -75,10 +80,10 @@ export function getCsvDelimiterValidationError(delimiter: string): CsvDelimiterV * Resolves a delimiter character to its corresponding preset identifier. * * Returns `"custom"` when the delimiter does not match any built-in preset, - * or the default preset id (`"comma"`) when no delimiter is provided. + * or `"inherit"` when the delimiter is `undefined` or an empty string. * - * @param delimiter - delimiter character to look up - * @returns the matching preset id, `"custom"`, or the default + * @param delimiter - delimiter character to look up; `undefined` or empty resolves to `"inherit"` + * @returns the matching preset id, `"custom"`, or `"inherit"` * @alpha */ export function getCsvDelimiterPreset(delimiter?: string): CsvDelimiterPreset { @@ -89,25 +94,35 @@ export function getCsvDelimiterPreset(delimiter?: string): CsvDelimiterPreset { } } - return delimiter ? "custom" : DEFAULT_CSV_DELIMITER_PRESET_ID; + return delimiter ? "custom" : "inherit"; } /** * Returns the actual delimiter character for a given preset selection. * * When the preset is `"custom"`, the provided custom delimiter string is returned as-is. + * When the preset is `"inherit"`, `undefined` is returned so the `delimiter` field is omitted + * from the saved settings, letting the backend-resolved default (workspace or organization + * setting) apply instead. * * @param selectedPreset - the selected preset identifier * @param customDelimiter - the user-provided custom delimiter (used only when preset is `"custom"`) - * @returns the resolved delimiter character + * @returns the resolved delimiter character, or `undefined` when the preset is `"inherit"` * @alpha */ -export function getCsvDelimiterValue(selectedPreset: CsvDelimiterPreset, customDelimiter: string): string { +export function getCsvDelimiterValue( + selectedPreset: CsvDelimiterPreset, + customDelimiter: string, +): string | undefined { + if (selectedPreset === "inherit") { + return undefined; + } + if (selectedPreset === "custom") { return customDelimiter; } - return CSV_DELIMITER_PRESETS[selectedPreset]?.delimiter ?? DEFAULT_CSV_DELIMITER; + return CSV_DELIMITER_PRESETS[selectedPreset].delimiter; } /** diff --git a/libs/sdk-model/src/exports/tests/csvDelimiter.test.ts b/libs/sdk-model/src/exports/tests/csvDelimiter.test.ts new file mode 100644 index 00000000000..2c260dd1a78 --- /dev/null +++ b/libs/sdk-model/src/exports/tests/csvDelimiter.test.ts @@ -0,0 +1,70 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { + getCsvDelimiterPreset, + getCsvDelimiterState, + getCsvDelimiterValidationError, + getCsvDelimiterValue, +} from "../csvDelimiter.js"; + +describe("getCsvDelimiterPreset", () => { + const Scenarios: Array<[string, string | undefined, string]> = [ + ["undefined", undefined, "inherit"], + ["empty string", "", "inherit"], + ["comma", ",", "comma"], + ["semicolon", ";", "semicolon"], + ["pipe", "|", "pipe"], + ["tab", "\t", "tab"], + ["custom character", "#", "custom"], + ]; + + it.each(Scenarios)("resolves %s to %s", (_desc, delimiter, expected) => { + expect(getCsvDelimiterPreset(delimiter)).toBe(expected); + }); +}); + +describe("getCsvDelimiterValue", () => { + it("returns undefined for the inherit preset", () => { + expect(getCsvDelimiterValue("inherit", "")).toBeUndefined(); + }); + + it("returns the custom delimiter as-is for the custom preset", () => { + expect(getCsvDelimiterValue("custom", "#")).toBe("#"); + }); + + it("returns the built-in character for a preset id", () => { + expect(getCsvDelimiterValue("comma", "")).toBe(","); + expect(getCsvDelimiterValue("tab", "")).toBe("\t"); + }); +}); + +describe("getCsvDelimiterState", () => { + it("maps undefined to the inherit preset with no custom delimiter", () => { + expect(getCsvDelimiterState(undefined)).toEqual({ selectedPreset: "inherit", customDelimiter: "" }); + }); + + it("maps a built-in character to its preset with no custom delimiter", () => { + expect(getCsvDelimiterState(",")).toEqual({ selectedPreset: "comma", customDelimiter: "" }); + }); + + it("maps an unrecognized character to the custom preset carrying that character", () => { + expect(getCsvDelimiterState("#")).toEqual({ selectedPreset: "custom", customDelimiter: "#" }); + }); +}); + +describe("getCsvDelimiterValidationError", () => { + it("rejects empty and multi-character values", () => { + expect(getCsvDelimiterValidationError("")).toBe("singleCharacter"); + expect(getCsvDelimiterValidationError("ab")).toBe("singleCharacter"); + }); + + it("rejects characters outside the supported set", () => { + expect(getCsvDelimiterValidationError("a")).toBe("unsupportedCharacter"); + }); + + it("accepts a supported single character", () => { + expect(getCsvDelimiterValidationError("#")).toBeUndefined(); + }); +}); diff --git a/libs/sdk-model/src/index.ts b/libs/sdk-model/src/index.ts index fa0e5e555bb..63b5f0000f2 100644 --- a/libs/sdk-model/src/index.ts +++ b/libs/sdk-model/src/index.ts @@ -611,6 +611,7 @@ export { type IRelativeDateFilterForm, type IRelativeDateFilterPreset, type IRelativeDateFilterPresetOfGranularity, + DEFAULT_ABSOLUTE_DATE_FILTER_GRANULARITIES, isAbsoluteDateFilterForm, isAbsoluteDateFilterPreset, isAllTimeDateFilterOption, @@ -814,6 +815,11 @@ export type { ICatalogGroup, IGroupableCatalogItemBase } from "./ldm/catalog/gro export { type ICatalogAttribute, isCatalogAttribute } from "./ldm/catalog/attribute/index.js"; +export { + type ICatalogComputedAttribute, + isCatalogComputedAttribute, +} from "./ldm/catalog/computedAttribute/index.js"; + export { type ICatalogFact, isCatalogFact } from "./ldm/catalog/fact/index.js"; export { type ICatalogMeasure, isCatalogMeasure } from "./ldm/catalog/measure/index.js"; @@ -840,6 +846,14 @@ export { type IDateHierarchyTemplate, isAttributeHierarchyMetadataObject, } from "./ldm/metadata/attributeHierarchy/index.js"; +export { + type ComputedAttributeDataType, + type IComputedAttributeMetadataObject, + type IComputedAttributeMetadataObjectBase, + type IComputedAttributeMetadataObjectDefinition, + isComputedAttributeMetadataObject, + isComputedAttributeMetadataObjectDefinition, +} from "./ldm/metadata/computedAttribute/index.js"; export { type IDashboardMetadataObject, isDashboardMetadataObject } from "./ldm/metadata/dashboard/index.js"; export { type IDataSetAttributeMetadataObject, diff --git a/libs/sdk-model/src/ldm/catalog/computedAttribute/index.ts b/libs/sdk-model/src/ldm/catalog/computedAttribute/index.ts new file mode 100644 index 00000000000..ce6ce11ea4d --- /dev/null +++ b/libs/sdk-model/src/ldm/catalog/computedAttribute/index.ts @@ -0,0 +1,48 @@ +// (C) 2026 GoodData Corporation + +import { isEmpty } from "lodash-es"; + +import { type IAttributeDisplayFormMetadataObject } from "../../metadata/attributeDisplayForm/index.js"; +import { type IComputedAttributeMetadataObject } from "../../metadata/computedAttribute/index.js"; +import { type IGroupableCatalogItemBase } from "../group/index.js"; + +/** + * Type representing catalog computed attribute. + * + * @remarks + * Shaped after {@link ICatalogAttribute} so it can be listed and dragged among + * normal attributes; `defaultDisplayForm` is the fabricated display form of the + * computed attribute (see {@link IComputedAttributeMetadataObject}). + * + * @public + */ +export interface ICatalogComputedAttribute extends IGroupableCatalogItemBase { + /** + * Catalog item type + */ + type: "computedAttribute"; + + /** + * Computed attribute metadata object that this catalog item represents + */ + computedAttribute: IComputedAttributeMetadataObject; + + /** + * Default (and only) display form of the computed attribute + */ + defaultDisplayForm: IAttributeDisplayFormMetadataObject; + + /** + * Display forms of the computed attribute + */ + displayForms: IAttributeDisplayFormMetadataObject[]; +} + +/** + * Type guard checking whether the provided object is a {@link ICatalogComputedAttribute} + * + * @public + */ +export function isCatalogComputedAttribute(obj: unknown): obj is ICatalogComputedAttribute { + return !isEmpty(obj) && (obj as ICatalogComputedAttribute).type === "computedAttribute"; +} diff --git a/libs/sdk-model/src/ldm/catalog/index.ts b/libs/sdk-model/src/ldm/catalog/index.ts index 551d3d0a955..6c65ba97832 100644 --- a/libs/sdk-model/src/ldm/catalog/index.ts +++ b/libs/sdk-model/src/ldm/catalog/index.ts @@ -4,12 +4,13 @@ import { type MetadataObject } from "../metadata/index.js"; import { type ICatalogAttribute, isCatalogAttribute } from "./attribute/index.js"; import { type ICatalogAttributeHierarchy, isCatalogAttributeHierarchy } from "./attributeHierarchy/index.js"; +import { type ICatalogComputedAttribute, isCatalogComputedAttribute } from "./computedAttribute/index.js"; import { type ICatalogDateDataset } from "./dateDataset/index.js"; import { type ICatalogFact, isCatalogFact } from "./fact/index.js"; import { type ICatalogMeasure, isCatalogMeasure } from "./measure/index.js"; /** - * Type representing catalog item - attribute, measure, fact or dateDataset + * Type representing catalog item - attribute, measure, fact, dateDataset or computedAttribute * * @public */ @@ -18,7 +19,8 @@ export type CatalogItem = | ICatalogMeasure | ICatalogFact | ICatalogDateDataset - | ICatalogAttributeHierarchy; + | ICatalogAttributeHierarchy + | ICatalogComputedAttribute; /** * Get metadata object that catalog item represents @@ -38,6 +40,8 @@ export const catalogItemMetadataObject = (catalogItem: CatalogItem): MetadataObj item = catalogItem.fact; } else if (isCatalogAttributeHierarchy(catalogItem)) { item = catalogItem.attributeHierarchy; + } else if (isCatalogComputedAttribute(catalogItem)) { + item = catalogItem.computedAttribute; } else { item = catalogItem.dataSet; } @@ -54,4 +58,8 @@ export const catalogItemMetadataObject = (catalogItem: CatalogItem): MetadataObj * * @public */ -export type GroupableCatalogItem = ICatalogAttribute | ICatalogMeasure | ICatalogFact; +export type GroupableCatalogItem = + | ICatalogAttribute + | ICatalogMeasure + | ICatalogFact + | ICatalogComputedAttribute; diff --git a/libs/sdk-model/src/ldm/catalog/types.ts b/libs/sdk-model/src/ldm/catalog/types.ts index 18329f17a74..82d84208240 100644 --- a/libs/sdk-model/src/ldm/catalog/types.ts +++ b/libs/sdk-model/src/ldm/catalog/types.ts @@ -1,11 +1,18 @@ -// (C) 2019-2020 GoodData Corporation +// (C) 2019-2026 GoodData Corporation /** - * Type representing catalog item type - attribute, measure, fact, dateDataset or attributeHierarchy + * Type representing catalog item type - attribute, measure, fact, dateDataset, attributeHierarchy + * or computedAttribute * * @public */ -export type CatalogItemType = "attribute" | "measure" | "fact" | "dateDataset" | "attributeHierarchy"; +export type CatalogItemType = + | "attribute" + | "measure" + | "fact" + | "dateDataset" + | "attributeHierarchy" + | "computedAttribute"; /** * Properties contained in each catalog item diff --git a/libs/sdk-model/src/ldm/metadata/computedAttribute/index.ts b/libs/sdk-model/src/ldm/metadata/computedAttribute/index.ts new file mode 100644 index 00000000000..9c272c380bc --- /dev/null +++ b/libs/sdk-model/src/ldm/metadata/computedAttribute/index.ts @@ -0,0 +1,139 @@ +// (C) 2026 GoodData Corporation + +import { type IAuditable, type IObjectCertification } from "../../../base/metadata.js"; +import { type IAttributeDisplayFormMetadataObject } from "../attributeDisplayForm/index.js"; +import { type IDataSetMetadataObject } from "../dataSet/index.js"; +import { type MetricType } from "../measure/index.js"; +import { type IMetadataObject, type IMetadataObjectDefinition, isMetadataObject } from "../types.js"; + +/** + * Data type of the computed attribute values. + * + * @public + */ +export type ComputedAttributeDataType = + | "INT" + | "STRING" + | "DATE" + | "NUMERIC" + | "TIMESTAMP" + | "TIMESTAMP_TZ" + | "BOOLEAN" + | "HLL"; + +/** + * @public + */ +export interface IComputedAttributeMetadataObjectBase { + type: "computedAttribute"; + + /** + * MAQL expression computing the attribute values. + */ + expression: string; + + /** + * Formatting of the computed values. + * If empty, a backend implementation-dependent default is used. + */ + format?: string; + + /** + * Categorizes the semantics of the computed values (e.g., currency). + */ + metricType?: MetricType; + + /** + * Data type of the computed values. + */ + dataType?: ComputedAttributeDataType; + + /** + * Whether the computed values may contain nulls. + */ + isNullable?: boolean; + + /** + * Value used in place of null computed values. + */ + nullValue?: string; + + /** + * Locale whose collation order the computed values are sorted by. + */ + locale?: string; +} + +/** + * Computed attribute metadata object. + * + * @remarks + * A computed attribute is an attribute whose values are computed by a MAQL expression + * instead of being backed by a data source column. It is deliberately shaped as close + * to {@link IAttributeMetadataObject} as possible so that UI treats it like a normal + * attribute wherever it appears (buckets, catalog, ...). + * + * @public + */ +export type IComputedAttributeMetadataObject = IMetadataObject & + IComputedAttributeMetadataObjectBase & + IAuditable & { + /** + * Display forms of the computed attribute. + * + * @remarks + * A computed attribute has no real labels on the backend. To mimic the structure of + * a normal attribute, the backend implementation fabricates exactly one display form + * (isDefault and isPrimary, attribute ref pointing to this computed attribute). + */ + displayForms: IAttributeDisplayFormMetadataObject[]; + + /** + * Whether the computed attribute is locked for editing (e.g. inherited from a parent workspace). + */ + isLocked?: boolean; + + /** + * Dataset the computed attribute belongs to (if supplied by backend include). + */ + dataSet?: IDataSetMetadataObject; + + /** + * Certification metadata. + * @internal + */ + certification?: IObjectCertification; + }; + +/** + * Computed attribute metadata object definition (not yet persisted). + * + * @public + */ +export type IComputedAttributeMetadataObjectDefinition = IMetadataObjectDefinition & + IComputedAttributeMetadataObjectBase; + +/** + * Tests whether the provided object is of type {@link IComputedAttributeMetadataObject}. + * + * @param obj - object to test + * @public + */ +export function isComputedAttributeMetadataObject(obj: unknown): obj is IComputedAttributeMetadataObject { + return isMetadataObject(obj) && obj.type === "computedAttribute"; +} + +/** + * Tests whether the provided object is of type {@link IComputedAttributeMetadataObjectDefinition}. + * + * @param obj - object to test + * @public + */ +export function isComputedAttributeMetadataObjectDefinition( + obj: unknown, +): obj is IComputedAttributeMetadataObjectDefinition { + return ( + (obj as IComputedAttributeMetadataObject).type === "computedAttribute" && + (obj as IComputedAttributeMetadataObject).ref === undefined + ); +} diff --git a/libs/sdk-model/src/ldm/metadata/index.ts b/libs/sdk-model/src/ldm/metadata/index.ts index 7edb6dc9ea5..f9f946e7411 100644 --- a/libs/sdk-model/src/ldm/metadata/index.ts +++ b/libs/sdk-model/src/ldm/metadata/index.ts @@ -3,6 +3,7 @@ import { type IAttributeMetadataObject } from "./attribute/index.js"; import { type IAttributeDisplayFormMetadataObject } from "./attributeDisplayForm/index.js"; import { type IAttributeHierarchyMetadataObject } from "./attributeHierarchy/index.js"; +import { type IComputedAttributeMetadataObject } from "./computedAttribute/index.js"; import { type IDashboardMetadataObject } from "./dashboard/index.js"; import { type IDataSetMetadataObject } from "./dataSet/index.js"; import { type IFactMetadataObject } from "./fact/index.js"; @@ -18,6 +19,7 @@ import { type IVariableMetadataObject } from "./variable/index.js"; */ export type MetadataObject = | IAttributeMetadataObject + | IComputedAttributeMetadataObject | IAttributeDisplayFormMetadataObject | IFactMetadataObject | IMeasureMetadataObject diff --git a/libs/sdk-model/src/objRef/index.ts b/libs/sdk-model/src/objRef/index.ts index 73cf39b83cd..7ad72e09644 100644 --- a/libs/sdk-model/src/objRef/index.ts +++ b/libs/sdk-model/src/objRef/index.ts @@ -40,6 +40,7 @@ export type ObjectType = | "measure" | "fact" | "attribute" + | "computedAttribute" | "displayForm" | "dataSet" | "tag" diff --git a/libs/sdk-model/src/settings/settings.ts b/libs/sdk-model/src/settings/settings.ts index 4f71c54cf1a..e2e89ced4d6 100644 --- a/libs/sdk-model/src/settings/settings.ts +++ b/libs/sdk-model/src/settings/settings.ts @@ -1165,4 +1165,14 @@ export interface IFeatureFlags { * Enable granularity selection for the absolute (static) date filter. */ enableAbsoluteDateFilterGranularity?: boolean; + + /** + * Enable computed attributes. + */ + enableComputedAttributes?: boolean; + + /** + * Enable the Business Briefing reports application. + */ + enableBusinessBriefingReportsApp?: boolean; } diff --git a/libs/sdk-pluggable-application-model/package.json b/libs/sdk-pluggable-application-model/package.json index 75200e3ef26..bfacac0f76f 100644 --- a/libs/sdk-pluggable-application-model/package.json +++ b/libs/sdk-pluggable-application-model/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-pluggable-application-model", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData SDK model contracts for pluggable applications", "license": "MIT", "author": "GoodData Corporation", diff --git a/libs/sdk-ui-all/package.json b/libs/sdk-ui-all/package.json index fecf86adab9..0c0c8304e52 100644 --- a/libs/sdk-ui-all/package.json +++ b/libs/sdk-ui-all/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-all", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData SDK - All-In-One", "license": "LicenseRef-LICENSE", "author": "GoodData", diff --git a/libs/sdk-ui-application-header/package.json b/libs/sdk-ui-application-header/package.json index 0a6c7517c1a..7019401caaa 100644 --- a/libs/sdk-ui-application-header/package.json +++ b/libs/sdk-ui-application-header/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-application-header", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData SDK application header components — workspace picker, notifications dropdown", "license": "MIT", "author": "GoodData Corporation", diff --git a/libs/sdk-ui-application-header/src/AppHeaderNotifications/dashboardUrl.test.ts b/libs/sdk-ui-application-header/src/AppHeaderNotifications/dashboardUrl.test.ts index aba82b5997e..3d75dfd87b7 100644 --- a/libs/sdk-ui-application-header/src/AppHeaderNotifications/dashboardUrl.test.ts +++ b/libs/sdk-ui-application-header/src/AppHeaderNotifications/dashboardUrl.test.ts @@ -1,5 +1,7 @@ // (C) 2025-2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { type INotification } from "@gooddata/sdk-model"; diff --git a/libs/sdk-ui-catalog/package.json b/libs/sdk-ui-catalog/package.json index 92c4fbcc18c..3519976aa06 100644 --- a/libs/sdk-ui-catalog/package.json +++ b/libs/sdk-ui-catalog/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-catalog", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData SDK - Analytics Catalog", "license": "MIT", "author": "GoodData Corporation", diff --git a/libs/sdk-ui-catalog/src/localization/bundles/pt-BR.json b/libs/sdk-ui-catalog/src/localization/bundles/pt-BR.json index 41f28bb874e..d21ff8eee42 100644 --- a/libs/sdk-ui-catalog/src/localization/bundles/pt-BR.json +++ b/libs/sdk-ui-catalog/src/localization/bundles/pt-BR.json @@ -10,7 +10,7 @@ "analyticsCatalog.objectType.fact.button.ariaLabel": "Fato: {count}", "analyticsCatalog.objectType.attribute.button.ariaLabel": "Atributo: {count}", "analyticsCatalog.objectType.dateDataset.button.ariaLabel": "Conjunto de dados de data: {count}", - "analyticsCatalog.objectType.dashboard.name": "Dashboard", + "analyticsCatalog.objectType.dashboard.name": "Painel", "analyticsCatalog.objectType.visualization.name": "Visualização", "analyticsCatalog.objectType.metric.name": "Métrica", "analyticsCatalog.objectType.attribute.name": "Atributo", diff --git a/libs/sdk-ui-catalog/src/localization/bundles/pt-PT.json b/libs/sdk-ui-catalog/src/localization/bundles/pt-PT.json index 421d405f2d4..ed1cc83744f 100644 --- a/libs/sdk-ui-catalog/src/localization/bundles/pt-PT.json +++ b/libs/sdk-ui-catalog/src/localization/bundles/pt-PT.json @@ -10,7 +10,7 @@ "analyticsCatalog.objectType.fact.button.ariaLabel": "Facto: {count}", "analyticsCatalog.objectType.attribute.button.ariaLabel": "Atributo: {count}", "analyticsCatalog.objectType.dateDataset.button.ariaLabel": "Conjunto de dados de data: {count}", - "analyticsCatalog.objectType.dashboard.name": "Dashboard", + "analyticsCatalog.objectType.dashboard.name": "Painel", "analyticsCatalog.objectType.visualization.name": "Visualização", "analyticsCatalog.objectType.metric.name": "Métrica", "analyticsCatalog.objectType.attribute.name": "Atributo", diff --git a/libs/sdk-ui-charts/package.json b/libs/sdk-ui-charts/package.json index e601ebf580d..9a80ce70aa1 100644 --- a/libs/sdk-ui-charts/package.json +++ b/libs/sdk-ui-charts/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-charts", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData.UI SDK - Charts", "license": "LicenseRef-LICENSE", "author": "GoodData Corporation", diff --git a/libs/sdk-ui-charts/src/charts/headline/CoreHeadline.test.tsx b/libs/sdk-ui-charts/src/charts/headline/CoreHeadline.test.tsx index 9a1e45b27c4..63430ec36f1 100644 --- a/libs/sdk-ui-charts/src/charts/headline/CoreHeadline.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/CoreHeadline.test.tsx @@ -6,8 +6,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; -import { recordedDataFacade } from "../../../testUtils/recordings.js"; import { type ICoreChartProps } from "../../interfaces/chartProps.js"; +import { recordedDataFacade } from "../../testUtils/recordings.fixture.js"; import { CoreHeadline, type ICoreHeadlineExtendedProps } from "./CoreHeadline.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/BaseHeadline.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/BaseHeadline.test.tsx index 54fb1760aef..0725ac79755 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/BaseHeadline.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/BaseHeadline.test.tsx @@ -6,7 +6,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { withIntlForTest } from "@gooddata/sdk-ui"; import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; -import { TEST_BASE_HEADLINE_ITEM } from "../../TestData.fixtures.js"; +import { TEST_BASE_HEADLINE_ITEM } from "../../tests/TestData.test.helpers.js"; import { BaseHeadline, type IHeadlineProps } from "./BaseHeadline.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSection.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSection.test.tsx index e7d547b92da..739944e8245 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSection.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSection.test.tsx @@ -9,7 +9,7 @@ import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; import { HEADLINE_PAGINATED_COMPARE_SECTION_SELECTOR, TEST_BASE_HEADLINE_ITEM, -} from "../../TestData.fixtures.js"; +} from "../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "./BaseHeadline.test.helpers.js"; import { CompareSection } from "./CompareSection.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSectionItem.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSectionItem.test.tsx index a3caf6b8ccc..5042effc81a 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSectionItem.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/CompareSectionItem.test.tsx @@ -6,7 +6,7 @@ import { render } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; -import { TEST_BASE_HEADLINE_ITEM } from "../../TestData.fixtures.js"; +import { TEST_BASE_HEADLINE_ITEM } from "../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "./BaseHeadline.test.helpers.js"; import { CompareSectionItem } from "./CompareSectionItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySection.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySection.test.tsx index 07278f6f905..2486dad44a8 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySection.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySection.test.tsx @@ -4,7 +4,7 @@ import { render } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; -import { TEST_BASE_HEADLINE_ITEM } from "../../TestData.fixtures.js"; +import { TEST_BASE_HEADLINE_ITEM } from "../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "./BaseHeadline.test.helpers.js"; import { PrimarySection } from "./PrimarySection.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionCompactContent.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionCompactContent.test.tsx index 7fb51dd6dfe..558409006fa 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionCompactContent.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionCompactContent.test.tsx @@ -4,7 +4,7 @@ import { render } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; -import { TEST_BASE_HEADLINE_ITEM } from "../../TestData.fixtures.js"; +import { TEST_BASE_HEADLINE_ITEM } from "../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "./BaseHeadline.test.helpers.js"; import { PrimarySectionCompactContent } from "./PrimarySectionCompactContent.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionContent.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionContent.test.tsx index 58e7d56a3b3..0f97cba0bb5 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionContent.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/PrimarySectionContent.test.tsx @@ -4,7 +4,7 @@ import { render } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IBaseHeadlineItem } from "../../interfaces/BaseHeadlines.js"; -import { TEST_BASE_HEADLINE_ITEM } from "../../TestData.fixtures.js"; +import { TEST_BASE_HEADLINE_ITEM } from "../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "./BaseHeadline.test.helpers.js"; import { PrimarySectionContent } from "./PrimarySectionContent.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.test.tsx index 27fa2b69440..111972b41d9 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.test.tsx @@ -12,7 +12,7 @@ import { HEADLINE_VALUE_WRAPPER_SELECTOR, TEST_DATA_ITEM, TEST_RENDER_VALUE_SPECS, -} from "../../../TestData.fixtures.js"; +} from "../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../BaseHeadline.test.helpers.js"; import { BaseHeadlineDataItem } from "./BaseHeadlineDataItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataItem.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataItem.test.tsx index f3c88920341..bc5730568f5 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataItem.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataItem.test.tsx @@ -19,7 +19,7 @@ import { TEST_DATA_ITEM, TEST_RENDER_COLOR_SPECS, createComparison, -} from "../../../../TestData.fixtures.js"; +} from "../../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../../BaseHeadline.test.helpers.js"; import { ComparisonDataItem } from "./ComparisonDataItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataWithSubItem.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataWithSubItem.test.tsx index f6968c59d9f..8f8bf2f0e7a 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataWithSubItem.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonDataWithSubItem.test.tsx @@ -15,7 +15,7 @@ import { TEST_DATA_WITH_SUB_ITEM, TEST_RENDER_COLOR_SPECS, createComparison, -} from "../../../../TestData.fixtures.js"; +} from "../../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../../BaseHeadline.test.helpers.js"; import { ComparisonDataWithSubItem } from "./ComparisonDataWithSubItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonValue.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonValue.test.tsx index a9c30ba06d9..0867738f4f3 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonValue.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/ComparisonValue.test.tsx @@ -8,7 +8,7 @@ import { beforeEach, describe, expect, it } from "vitest"; import { withIntlForTest } from "@gooddata/sdk-ui"; import { type IBaseHeadlineValueItem } from "../../../../interfaces/BaseHeadlines.js"; -import { TEST_DATA_ITEM, TEST_RENDER_VALUE_SPECS } from "../../../../TestData.fixtures.js"; +import { TEST_DATA_ITEM, TEST_RENDER_VALUE_SPECS } from "../../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../../BaseHeadline.test.helpers.js"; import { ComparisonValue } from "./ComparisonValue.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/useComparisonDataItem.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/useComparisonDataItem.test.ts index 8e32573c7d8..2f190b9f11f 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/useComparisonDataItem.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/comparisonItems/useComparisonDataItem.test.ts @@ -9,7 +9,7 @@ import { TEST_COLOR_CONFIGS, TEST_COMPARISON_PALETTE, createComparison, -} from "../../../../TestData.fixtures.js"; +} from "../../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../../BaseHeadline.test.helpers.js"; import { useComparisonDataItem } from "./useComparisonDataItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/useBaseHeadlineDataItem.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/useBaseHeadlineDataItem.test.ts index 3078f83df5a..da0635fe6ce 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/useBaseHeadlineDataItem.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/useBaseHeadlineDataItem.test.ts @@ -3,7 +3,7 @@ import { renderHook } from "@testing-library/react"; import { beforeEach, describe, expect, it } from "vitest"; -import { TEST_DATA_ITEM } from "../../../TestData.fixtures.js"; +import { TEST_DATA_ITEM } from "../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../BaseHeadline.test.helpers.js"; import { useBaseHeadlineDataItem } from "./useBaseHeadlineDataItem.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withDrillable.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withDrillable.test.tsx index fba6057c1ed..f059026ede8 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withDrillable.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withDrillable.test.tsx @@ -10,7 +10,7 @@ import { type IWithDrillableItemProps, } from "../../../interfaces/BaseHeadlines.js"; import { type IHeadlineDataItem } from "../../../interfaces/Headlines.js"; -import { HEADLINE_ITEM_LINK_SELECTOR, TEST_DATA_ITEM } from "../../../TestData.fixtures.js"; +import { HEADLINE_ITEM_LINK_SELECTOR, TEST_DATA_ITEM } from "../../../tests/TestData.test.helpers.js"; import { createBaseHeadlineTestContext } from "../BaseHeadline.test.helpers.js"; import { withDrillable } from "./withDrillable.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withTitle.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withTitle.test.tsx index 485b24a94d5..36fd7bca061 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withTitle.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/headlines/baseHeadline/baseHeadlineDataItems/withTitle.test.tsx @@ -4,7 +4,7 @@ import { render } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import { type IBaseHeadlineTitle, type IWithTitleProps } from "../../../interfaces/BaseHeadlines.js"; -import { HEADLINE_TITLE_WRAPPER_SELECTOR, TEST_DATA_ITEM } from "../../../TestData.fixtures.js"; +import { HEADLINE_TITLE_WRAPPER_SELECTOR, TEST_DATA_ITEM } from "../../../tests/TestData.test.helpers.js"; import { withTitle } from "./withTitle.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/providers/AbstractProvider.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/providers/AbstractProvider.test.ts index ac5dff86b2d..b21f6531e82 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/providers/AbstractProvider.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/providers/AbstractProvider.test.ts @@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest"; -import { MockProvider } from "./MockProvider.js"; +import { MockProvider } from "./MockProvider.test.helpers.js"; import { TEST_BUCKETS, TEST_DATE_FORMAT, @@ -12,7 +12,7 @@ import { TEST_EXECUTION_FACTORY, TEST_FILTERS, TEST_SORT_ITEMS, -} from "./TestData.fixtures.js"; +} from "./TestData.test.helpers.js"; describe("AbstractProvider", () => { const provider = new MockProvider(); diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/providers/ComparisonProvider.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/providers/ComparisonProvider.test.ts index 03135bb2441..0a41fe8686f 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/providers/ComparisonProvider.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/providers/ComparisonProvider.test.ts @@ -14,7 +14,7 @@ import { TEST_EXECUTION_FACTORY, TEST_FILTERS, TEST_SORT_ITEMS, -} from "./TestData.fixtures.js"; +} from "./TestData.test.helpers.js"; describe("ComparisonProvider", () => { const newProvider = (comparison: IComparison) => { diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/providers/MockProvider.ts b/libs/sdk-ui-charts/src/charts/headline/internal/providers/MockProvider.test.helpers.ts similarity index 100% rename from libs/sdk-ui-charts/src/charts/headline/internal/providers/MockProvider.ts rename to libs/sdk-ui-charts/src/charts/headline/internal/providers/MockProvider.test.helpers.ts diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/providers/TestData.fixtures.ts b/libs/sdk-ui-charts/src/charts/headline/internal/providers/TestData.test.helpers.ts similarity index 100% rename from libs/sdk-ui-charts/src/charts/headline/internal/providers/TestData.fixtures.ts rename to libs/sdk-ui-charts/src/charts/headline/internal/providers/TestData.test.helpers.ts diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/TestData.fixtures.ts b/libs/sdk-ui-charts/src/charts/headline/internal/tests/TestData.test.helpers.ts similarity index 97% rename from libs/sdk-ui-charts/src/charts/headline/internal/TestData.fixtures.ts rename to libs/sdk-ui-charts/src/charts/headline/internal/tests/TestData.test.helpers.ts index f7f62f3c4a2..bd52895a057 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/TestData.fixtures.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/tests/TestData.test.helpers.ts @@ -9,16 +9,15 @@ import { ComparisonPositionValues, type IColorConfig, type IComparison, -} from "../../../interfaces/comparison.js"; -import { ComparisonColorType } from "../headlineHelper.js"; - -import { BaseHeadlineDataItem } from "./headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.js"; +} from "../../../../interfaces/comparison.js"; +import { ComparisonColorType } from "../../headlineHelper.js"; +import { BaseHeadlineDataItem } from "../headlines/baseHeadline/baseHeadlineDataItems/BaseHeadlineDataItem.js"; import { EvaluationType, type IBaseHeadlineItem, type IComparisonDataWithSubItem, -} from "./interfaces/BaseHeadlines.js"; -import { type IHeadlineDataItem } from "./interfaces/Headlines.js"; +} from "../interfaces/BaseHeadlines.js"; +import { type IHeadlineDataItem } from "../interfaces/Headlines.js"; export const createComparison = (customConfig: Omit = {}) => { return { diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/transformations/ComparisonTransformation.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/transformations/ComparisonTransformation.test.tsx index 813c7dcab39..60597bbd848 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/transformations/ComparisonTransformation.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/transformations/ComparisonTransformation.test.tsx @@ -7,12 +7,12 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { type ExplicitDrill, createIntlMock } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../../testUtils/recordings.js"; import { type IChartConfig } from "../../../../interfaces/chartConfig.js"; import { type IComparison } from "../../../../interfaces/comparison.js"; +import { recordedDataFacade } from "../../../../testUtils/recordings.fixture.js"; import { type IHeadlineTransformationProps } from "../../HeadlineProvider.js"; import { BaseHeadline } from "../headlines/baseHeadline/BaseHeadline.js"; -import { TEST_COMPARISON_TRANSFORMATIONS, TEST_DEFAULT_COMPARISON } from "../TestData.fixtures.js"; +import { TEST_COMPARISON_TRANSFORMATIONS, TEST_DEFAULT_COMPARISON } from "../tests/TestData.test.helpers.js"; import { getComparisonBaseHeadlineData } from "../utils/ComparisonTransformationUtils.js"; import { ComparisonTransformation } from "./ComparisonTransformation.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/transformations/MultiMeasuresTransformation.test.tsx b/libs/sdk-ui-charts/src/charts/headline/internal/transformations/MultiMeasuresTransformation.test.tsx index 99e4e1dcbf0..998053b5ab8 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/transformations/MultiMeasuresTransformation.test.tsx +++ b/libs/sdk-ui-charts/src/charts/headline/internal/transformations/MultiMeasuresTransformation.test.tsx @@ -6,9 +6,9 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { type ExplicitDrill, withIntlForTest } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../../testUtils/recordings.fixture.js"; import { type IHeadlineTransformationProps } from "../../HeadlineProvider.js"; -import { TEST_MULTI_MEASURE_TRANSFORMATION } from "../TestData.fixtures.js"; +import { TEST_MULTI_MEASURE_TRANSFORMATION } from "../tests/TestData.test.helpers.js"; vi.mock("../headlines/baseHeadline/BaseHeadline.js", async (importOriginal) => { const original = await importOriginal(); diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/utils/BaseHeadlineTransformationUtils.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/utils/BaseHeadlineTransformationUtils.test.ts index 8500a0c4ae9..bae296a70e5 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/utils/BaseHeadlineTransformationUtils.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/utils/BaseHeadlineTransformationUtils.test.ts @@ -8,8 +8,8 @@ import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { DataViewFacade, type ExplicitDrill, type HeadlineElementType } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../../testUtils/recordings.js"; -import { TEST_MULTI_MEASURE_TRANSFORMATION } from "../TestData.fixtures.js"; +import { recordedDataFacade } from "../../../../testUtils/recordings.fixture.js"; +import { TEST_MULTI_MEASURE_TRANSFORMATION } from "../tests/TestData.test.helpers.js"; import { createBaseHeadlineItem, getBaseHeadlineData } from "./BaseHeadlineTransformationUtils.js"; import { getExecutionData } from "./HeadlineTransformationUtils.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonDataItemUtils.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonDataItemUtils.test.ts index f11169b87a2..9791d3ff210 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonDataItemUtils.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonDataItemUtils.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { EvaluationType } from "../interfaces/BaseHeadlines.js"; -import { TEST_COLOR_CONFIGS, TEST_COMPARISON_PALETTE } from "../TestData.fixtures.js"; +import { TEST_COLOR_CONFIGS, TEST_COMPARISON_PALETTE } from "../tests/TestData.test.helpers.js"; import { getComparisonColor } from "./ComparisonDataItemUtils.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonTransformationUtils.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonTransformationUtils.test.ts index 62488cbfc2c..fc6ee909f16 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonTransformationUtils.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/utils/ComparisonTransformationUtils.test.ts @@ -7,9 +7,9 @@ import { describe, expect, it } from "vitest"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { type ExplicitDrill, createIntlMock } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../../testUtils/recordings.js"; import { type IComparison } from "../../../../interfaces/comparison.js"; -import { TEST_COMPARISON_TRANSFORMATIONS, TEST_DEFAULT_COMPARISON } from "../TestData.fixtures.js"; +import { recordedDataFacade } from "../../../../testUtils/recordings.fixture.js"; +import { TEST_COMPARISON_TRANSFORMATIONS, TEST_DEFAULT_COMPARISON } from "../tests/TestData.test.helpers.js"; import { getComparisonBaseHeadlineData } from "./ComparisonTransformationUtils.js"; diff --git a/libs/sdk-ui-charts/src/charts/headline/internal/utils/HeadlineTransformationUtils.test.ts b/libs/sdk-ui-charts/src/charts/headline/internal/utils/HeadlineTransformationUtils.test.ts index eb7876481b4..5e9f123ed83 100644 --- a/libs/sdk-ui-charts/src/charts/headline/internal/utils/HeadlineTransformationUtils.test.ts +++ b/libs/sdk-ui-charts/src/charts/headline/internal/utils/HeadlineTransformationUtils.test.ts @@ -18,7 +18,7 @@ import { headlineWithTwoMeasuresSecondEmpty, headlineWithTwoMeasuresSecondZero, headlineWithTwoMeasuresWithIdentifier, -} from "../../../../../testUtils/fixtures.js"; +} from "../../../../testUtils/charts.fixtures.js"; import { type IHeadlineData } from "../interfaces/Headlines.js"; import { diff --git a/libs/sdk-ui-charts/src/highcharts/ChartTransformation.test.tsx b/libs/sdk-ui-charts/src/highcharts/ChartTransformation.test.tsx index 1003e377ee6..99d535b9a30 100644 --- a/libs/sdk-ui-charts/src/highcharts/ChartTransformation.test.tsx +++ b/libs/sdk-ui-charts/src/highcharts/ChartTransformation.test.tsx @@ -8,10 +8,10 @@ import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { measureLocalId } from "@gooddata/sdk-model"; import { DataViewFacade, IntlWrapper, VisualizationTypes, withIntlForTest } from "@gooddata/sdk-ui"; -import { PieChartWithMetricsOnlyFundata } from "../../testUtils/fixturesData/PieChartWithMetricsOnlyFundata.js"; -import { localDataView } from "../../testUtils/localDataView.js"; -import { recordedDataFacade } from "../../testUtils/recordings.js"; import { type IChartConfig } from "../interfaces/chartConfig.js"; +import { PieChartWithMetricsOnlyFundata } from "../testUtils/fixturesData/PieChartWithMetricsOnlyFundata.fixture.js"; +import { localDataView } from "../testUtils/localDataView.fixture.js"; +import { recordedDataFacade } from "../testUtils/recordings.fixture.js"; import { HighChartsRenderer } from "./adapter/HighChartsRenderer.js"; import { ChartTransformation } from "./ChartTransformation.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/adapter/legendBuilder.test.ts b/libs/sdk-ui-charts/src/highcharts/adapter/legendBuilder.test.ts index c5cbe2c23d0..778fa7b1374 100644 --- a/libs/sdk-ui-charts/src/highcharts/adapter/legendBuilder.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/adapter/legendBuilder.test.ts @@ -10,7 +10,7 @@ import { measureLocalId } from "@gooddata/sdk-model"; import { VisualizationTypes } from "@gooddata/sdk-ui"; import { DEFAULT_LEGEND_CONFIG } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../testUtils/recordings.fixture.js"; import { generateChartOptions } from "../chartTypes/_util/helper.js"; import { buildLegendOptions, getLegendItems, shouldLegendBeEnabled } from "./legendBuilder.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/measure.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/measure.test.ts index 9da254ecaa4..1762355a26f 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/measure.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/measure.test.ts @@ -10,11 +10,11 @@ import { type IColorPalette, type ITheme } from "@gooddata/sdk-model"; import { HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; import { getMVS } from "../_util/helper.js"; +import { TwoColorPalette } from "../tests/color.test.helpers.js"; -import { TwoColorPalette } from "./color.fixture.js"; import { getColorsFromStrategy } from "./helper.js"; import { MeasureColorStrategy } from "./measure.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.test.ts deleted file mode 100644 index e86cae83f94..00000000000 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -// (C) 2019-2026 GoodData Corporation - -// @vitest-environment node - -import { describe, expect, it } from "vitest"; - -import { type IChartConfig } from "../../../interfaces/chartConfig.js"; -import { TOP } from "../../constants/alignments.js"; - -import { getChartAlignmentConfiguration } from "./getChartAlignmentConfiguration.js"; - -describe("getChartAlignmentConfiguration", () => { - it("should return chart alignment", () => { - const chartConfig: Partial = getChartAlignmentConfiguration(null as any, null as any, { - chart: { - verticalAlign: TOP, - }, - }); - expect(chartConfig).toEqual({ - chart: { - verticalAlign: "top", - }, - }); - }); - - it("should return empty chart alignment", () => { - const chartConfig: Partial = getChartAlignmentConfiguration( - null as any, - null as any, - {}, - ); - expect(chartConfig).toEqual({ - chart: undefined, - }); - }); -}); diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.ts deleted file mode 100644 index 071889eb821..00000000000 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartCreators/getChartAlignmentConfiguration.ts +++ /dev/null @@ -1,13 +0,0 @@ -// (C) 2019-2026 GoodData Corporation - -import { type IChartConfig } from "../../../interfaces/chartConfig.js"; -import { type IChartOptions } from "../../typings/unsafe.js"; - -export function getChartAlignmentConfiguration( - _chartOptions: IChartOptions, - _config: unknown, - chartConfig: IChartConfig = {}, -): Partial { - const { chart } = chartConfig; - return { chart }; -} diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartOptionsBuilder.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartOptionsBuilder.test.ts index 2b7fb1b673f..b3c52fa523a 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartOptionsBuilder.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartOptionsBuilder.test.ts @@ -21,6 +21,7 @@ import { getRgbString, } from "@gooddata/sdk-ui-vis-commons"; +import { type IChartConfig } from "../../../interfaces/chartConfig.js"; import { areaChartWith3MetricsAndViewByAttribute, areaChartWithMeasureViewByAndStackBy, @@ -51,9 +52,8 @@ import { treemapWithMetricAndViewByAttribute, treemapWithMetricViewByAndStackByAttribute, treemapWithTwoMetricsAndStackByAttribute, -} from "../../../../testUtils/fixtures.js"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; -import { type IChartConfig } from "../../../interfaces/chartConfig.js"; +} from "../../../testUtils/charts.fixtures.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { DEFAULT_CATEGORIES_LIMIT, PIE_CHART_LIMIT, diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartTooltips.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartTooltips.test.ts index 41c9034c128..df77ad5df8f 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartTooltips.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/chartTooltips.test.ts @@ -5,8 +5,8 @@ import { describe, expect, it } from "vitest"; import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; import { type IChartConfig } from "../../../interfaces/chartConfig.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { type IUnwrappedAttributeHeadersWithItems } from "../../typings/mess.js"; import { type IAxis, type IUnsafeHighchartsTooltipPoint } from "../../typings/unsafe.js"; import { getMVS } from "../_util/helper.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/dualAxis.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/dualAxis.test.ts index 23d79c85bc5..62defb8f3d6 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/dualAxis.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/dualAxis.test.ts @@ -7,8 +7,8 @@ import { describe, expect, it } from "vitest"; import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; import { type IChartConfig } from "../../../interfaces/chartConfig.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { setMeasuresToSecondaryAxis } from "./dualAxis.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/extendedStackingChartOptions.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/extendedStackingChartOptions.test.ts index a401645a0ce..81c323c9ece 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/extendedStackingChartOptions.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartOptions/extendedStackingChartOptions.test.ts @@ -15,7 +15,7 @@ import { import { DefaultColorPalette, HeaderPredicates } from "@gooddata/sdk-ui"; import { type ChartFillType } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { type IUnwrappedAttributeHeadersWithItems } from "../../typings/mess.js"; import { MeasureColorStrategy } from "../_chartColoring/measure.js"; import { getMVSForViewByTwoAttributes } from "../_util/helper.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/executionResultHelper.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/executionResultHelper.test.ts index d8af607222f..55f6d9928cc 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/executionResultHelper.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/executionResultHelper.test.ts @@ -8,7 +8,7 @@ import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { type IAttributeDescriptor, type IMeasureGroupDescriptor } from "@gooddata/sdk-model"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { findAttributeInDimension, findMeasureGroupInDimensions } from "./executionResultHelper.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/helper.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/helper.ts index a345eff4f1a..9501ffb1fe2 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/helper.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/helper.ts @@ -5,7 +5,7 @@ import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { type IMeasureGroupDescriptor } from "@gooddata/sdk-model"; import { type DataViewFacade, type IHeaderPredicate } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { PARENT_ATTRIBUTE_INDEX, PRIMARY_ATTRIBUTE_INDEX, diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/bubbleChart/bubbleChart.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/bubbleChart/bubbleChart.test.ts index 921377c12f3..3bddc705a47 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/bubbleChart/bubbleChart.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/bubbleChart/bubbleChart.test.ts @@ -9,10 +9,10 @@ import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; import { getMVS } from "../_util/helper.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; import { BubbleChartColorStrategy } from "./bubbleChartColoring.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChart.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChart.test.ts index 414d22ba5dc..95f6ad384c5 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChart.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChart.test.ts @@ -11,9 +11,9 @@ import { type IColorPalette, type IMeasure, type ITheme } from "@gooddata/sdk-mo import { type DataViewFacade, HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping, type IColorStrategy } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; const defaultColorMapping: IColorMapping[] = [ { diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChartOptions.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChartOptions.test.ts index 0e69aa9522e..ffe3ea56a80 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChartOptions.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/bulletChart/bulletChartOptions.test.ts @@ -11,7 +11,7 @@ import { type IColorPalette } from "@gooddata/sdk-model"; import { type DataViewFacade } from "@gooddata/sdk-ui"; import { type ChartFillType } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { BulletChartColorStrategy } from "./bulletChartColoring.js"; import { getBulletChartSeries } from "./bulletChartSeries.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/comboChart/comboChartOptions.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/comboChart/comboChartOptions.test.ts index 4d3a0888f41..934fe11e7d1 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/comboChart/comboChartOptions.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/comboChart/comboChartOptions.test.ts @@ -8,7 +8,7 @@ import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { VisualizationTypes } from "@gooddata/sdk-ui"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { type StackingType } from "../../constants/stacking.js"; import { type ISeriesItem } from "../../typings/unsafe.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/heatmap/heatmap.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/heatmap/heatmap.test.ts index 6c7e2830c2e..26b7127866d 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/heatmap/heatmap.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/heatmap/heatmap.test.ts @@ -11,11 +11,11 @@ import { type IColorPalette, type ITheme } from "@gooddata/sdk-model"; import { HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping, type IColorStrategy } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; import { HEATMAP_BLUE_COLOR_PALETTE } from "../_util/color.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; import { getMVS } from "../_util/helper.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; import { HeatmapColorStrategy } from "./heatmapColoring.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChart.fixture.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChart.test.helpers.ts similarity index 100% rename from libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChart.fixture.ts rename to libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChart.test.helpers.ts diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartColoring.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartColoring.test.ts index d972df83221..8ae9edfd6ad 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartColoring.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartColoring.test.ts @@ -6,12 +6,12 @@ import { describe, expect, it } from "vitest"; import { type IColorStrategy } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; import { getMVSForViewByTwoAttributes } from "../_util/helper.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; -import { CHART_TYPE, COLOR_MAPPINGS, RECORDS_WITHOUT_EMPTY_ATTRIBUTE } from "./sankeyChart.fixture.js"; +import { CHART_TYPE, COLOR_MAPPINGS, RECORDS_WITHOUT_EMPTY_ATTRIBUTE } from "./sankeyChart.test.helpers.js"; import { SankeyChartColorStrategy } from "./sankeyChartColoring.js"; describe("SankeyChartColorStrategy", () => { diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartOptions.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartOptions.test.ts index 565d6782680..293a320cd13 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartOptions.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartOptions.test.ts @@ -6,12 +6,12 @@ import { describe, expect, it } from "vitest"; import { type IColorStrategy } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; import { getMVSForViewByTwoAttributes } from "../_util/helper.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; -import { CHART_TYPE, COLOR_MAPPINGS, EMPTY_HEADER_TITLE_VALUE, RECORDS } from "./sankeyChart.fixture.js"; +import { CHART_TYPE, COLOR_MAPPINGS, EMPTY_HEADER_TITLE_VALUE, RECORDS } from "./sankeyChart.test.helpers.js"; import { buildSankeyChartSeries } from "./sankeyChartOptions.js"; describe("SankeyChart buildSankeyChartSeries", () => { diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartTooltip.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartTooltip.test.ts index fbe4478e9f0..c4604a4341c 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartTooltip.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/sankeyChart/sankeyChartTooltip.test.ts @@ -6,11 +6,11 @@ import { describe, expect, it } from "vitest"; import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { generateTooltipSankeyChartFn } from "../_chartOptions/chartTooltips.js"; import { getMVSForViewByTwoAttributes } from "../_util/helper.js"; -import { DEFAULT_TOOLTIP_CONTENT_WIDTH } from "./sankeyChart.fixture.js"; +import { DEFAULT_TOOLTIP_CONTENT_WIDTH } from "./sankeyChart.test.helpers.js"; describe("SankeyChart tooltip", () => { it("should render tooltip for node correctly", () => { diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/scatterPlot/scatterPlot.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/scatterPlot/scatterPlot.test.ts index 9339177fe47..ed7febddb26 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/scatterPlot/scatterPlot.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/scatterPlot/scatterPlot.test.ts @@ -10,10 +10,10 @@ import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping, type IColorStrategy } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; -import { CUSTOM_COLOR_PALETTE } from "../_util/colorPalette.fixture.js"; import { getMVS } from "../_util/helper.js"; +import { CUSTOM_COLOR_PALETTE } from "../tests/colorPalette.test.helpers.js"; import { ScatterPlotColorStrategy } from "./scatterPlotColoring.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/color.fixture.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/tests/color.test.helpers.ts similarity index 100% rename from libs/sdk-ui-charts/src/highcharts/chartTypes/_chartColoring/color.fixture.ts rename to libs/sdk-ui-charts/src/highcharts/chartTypes/tests/color.test.helpers.ts diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/_util/colorPalette.fixture.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/tests/colorPalette.test.helpers.ts similarity index 100% rename from libs/sdk-ui-charts/src/highcharts/chartTypes/_util/colorPalette.fixture.ts rename to libs/sdk-ui-charts/src/highcharts/chartTypes/tests/colorPalette.test.helpers.ts diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/treemap/treemap.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/treemap/treemap.test.ts index 939762d422e..616024a308f 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/treemap/treemap.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/treemap/treemap.test.ts @@ -10,11 +10,11 @@ import { type IColorPalette, type IColorPaletteItem } from "@gooddata/sdk-model" import { DefaultColorPalette, HeaderPredicates } from "@gooddata/sdk-ui"; import { type IColorMapping, getRgbString } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; -import { TwoColorPalette } from "../_chartColoring/color.fixture.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { getColorsFromStrategy } from "../_chartColoring/helper.js"; import { ColorFactory } from "../_chartOptions/colorFactory.js"; import { getMVS } from "../_util/helper.js"; +import { TwoColorPalette } from "../tests/color.test.helpers.js"; import { TreemapColorStrategy } from "./treemapColoring.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartOptions.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartOptions.test.ts index e4f10fcc90e..02d74f308d4 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartOptions.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartOptions.test.ts @@ -10,8 +10,8 @@ import { type IColorDescriptor } from "@gooddata/sdk-model"; import { DefaultColorPalette, type IColorAssignment, localIdentifierMatch } from "@gooddata/sdk-ui"; import { type ChartFillType } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; import { type IChartConfig, type ITotalConfig } from "../../../interfaces/chartConfig.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { type ISeriesItem } from "../../typings/unsafe.js"; import { getDrillableSeries } from "../_chartOptions/chartDrilling.js"; import { getMVS } from "../_util/helper.js"; diff --git a/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartsSeries.test.ts b/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartsSeries.test.ts index e3e13cc2872..8423c475aee 100644 --- a/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartsSeries.test.ts +++ b/libs/sdk-ui-charts/src/highcharts/chartTypes/waterfallChart/waterfallChartsSeries.test.ts @@ -9,7 +9,7 @@ import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { DefaultColorPalette } from "@gooddata/sdk-ui"; import { type ChartFillType } from "@gooddata/sdk-ui-vis-commons"; -import { recordedDataFacade } from "../../../../testUtils/recordings.js"; +import { recordedDataFacade } from "../../../testUtils/recordings.fixture.js"; import { getMVS } from "../_util/helper.js"; import { WaterfallChartColorStrategy } from "./waterfallChartColoring.js"; diff --git a/libs/sdk-ui-charts/testUtils/fixtures.ts b/libs/sdk-ui-charts/src/testUtils/charts.fixtures.ts similarity index 87% rename from libs/sdk-ui-charts/testUtils/fixtures.ts rename to libs/sdk-ui-charts/src/testUtils/charts.fixtures.ts index 1791666a758..a03b9deb1e9 100644 --- a/libs/sdk-ui-charts/testUtils/fixtures.ts +++ b/libs/sdk-ui-charts/src/testUtils/charts.fixtures.ts @@ -4,31 +4,31 @@ import { ReferenceRecordings } from "@gooddata/reference-workspace"; import { type ScenarioRecording } from "@gooddata/sdk-backend-mockingbird"; import { DataViewFacade } from "@gooddata/sdk-ui"; -import { AreaChartWith3MetricsAndViewByAttribute } from "./fixturesData/AreaChartWith3MetricsAndViewByAttribute.js"; -import { BarChartWith3MetricsAndViewByAttribute } from "./fixturesData/BarChartWith3MetricsAndViewByAttribute.js"; -import { BarChartWith3MetricsAndViewByAttributeFunformat } from "./fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.js"; -import { BarChartWith3MetricsAndViewByAttributePercInFormat } from "./fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.js"; -import { BarChartWith4MetricsAndViewByTwoAttributes } from "./fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.js"; -import { BarChartWithPopMeasureAndViewByAttribute } from "./fixturesData/BarChartWithPopMeasureAndViewByAttribute.js"; -import { BarChartWithPopMeasureAndViewByAttributeX6 } from "./fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.js"; -import { BarChartWithPreviousPeriodMeasure } from "./fixturesData/BarChartWithPreviousPeriodMeasure.js"; -import { BarChartWithPreviousPeriodMeasureX6 } from "./fixturesData/BarChartWithPreviousPeriodMeasureX6.js"; -import { BubbleChartWith3MetricsAndAttributeNullsInData } from "./fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.js"; -import { ComboChartWithTwoMeasuresViewByAttribute } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttribute.js"; -import { ComboChartWithTwoMeasuresViewByAttributeNoBuckets } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.js"; -import { ComboChartWithTwoMeasuresViewByAttributePercformat } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.js"; -import { HeadlineWithTwoMeasuresBothEmpty } from "./fixturesData/HeadlineWithTwoMeasuresBothEmpty.js"; -import { HeadlineWithTwoMeasuresBothSame } from "./fixturesData/HeadlineWithTwoMeasuresBothSame.js"; -import { HeadlineWithTwoMeasuresBothZero } from "./fixturesData/HeadlineWithTwoMeasuresBothZero.js"; -import { HeadlineWithTwoMeasuresFirstEmpty } from "./fixturesData/HeadlineWithTwoMeasuresFirstEmpty.js"; -import { HeadlineWithTwoMeasuresFirstZero } from "./fixturesData/HeadlineWithTwoMeasuresFirstZero.js"; -import { HeadlineWithTwoMeasuresSecondEmpty } from "./fixturesData/HeadlineWithTwoMeasuresSecondEmpty.js"; -import { HeadlineWithTwoMeasuresSecondZero } from "./fixturesData/HeadlineWithTwoMeasuresSecondZero.js"; -import { PieChartWithMetricsOnly } from "./fixturesData/PieChartWithMetricsOnly.js"; -import { PieChartWithMetricsOnlyFundata } from "./fixturesData/PieChartWithMetricsOnlyFundata.js"; -import { ScatterPlotWith2MetricsAndAttributeNullsInData } from "./fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.js"; -import { type ILocalExecutionRecording, localDataView } from "./localDataView.js"; -import { recordedDataFacade } from "./recordings.js"; +import { AreaChartWith3MetricsAndViewByAttribute } from "./fixturesData/AreaChartWith3MetricsAndViewByAttribute.fixture.js"; +import { BarChartWith3MetricsAndViewByAttribute } from "./fixturesData/BarChartWith3MetricsAndViewByAttribute.fixture.js"; +import { BarChartWith3MetricsAndViewByAttributeFunformat } from "./fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.fixture.js"; +import { BarChartWith3MetricsAndViewByAttributePercInFormat } from "./fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.fixture.js"; +import { BarChartWith4MetricsAndViewByTwoAttributes } from "./fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.fixture.js"; +import { BarChartWithPopMeasureAndViewByAttribute } from "./fixturesData/BarChartWithPopMeasureAndViewByAttribute.fixture.js"; +import { BarChartWithPopMeasureAndViewByAttributeX6 } from "./fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.fixture.js"; +import { BarChartWithPreviousPeriodMeasure } from "./fixturesData/BarChartWithPreviousPeriodMeasure.fixture.js"; +import { BarChartWithPreviousPeriodMeasureX6 } from "./fixturesData/BarChartWithPreviousPeriodMeasureX6.fixture.js"; +import { BubbleChartWith3MetricsAndAttributeNullsInData } from "./fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.fixture.js"; +import { ComboChartWithTwoMeasuresViewByAttribute } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttribute.fixture.js"; +import { ComboChartWithTwoMeasuresViewByAttributeNoBuckets } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.fixture.js"; +import { ComboChartWithTwoMeasuresViewByAttributePercformat } from "./fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.fixture.js"; +import { HeadlineWithTwoMeasuresBothEmpty } from "./fixturesData/HeadlineWithTwoMeasuresBothEmpty.fixture.js"; +import { HeadlineWithTwoMeasuresBothSame } from "./fixturesData/HeadlineWithTwoMeasuresBothSame.fixture.js"; +import { HeadlineWithTwoMeasuresBothZero } from "./fixturesData/HeadlineWithTwoMeasuresBothZero.fixture.js"; +import { HeadlineWithTwoMeasuresFirstEmpty } from "./fixturesData/HeadlineWithTwoMeasuresFirstEmpty.fixture.js"; +import { HeadlineWithTwoMeasuresFirstZero } from "./fixturesData/HeadlineWithTwoMeasuresFirstZero.fixture.js"; +import { HeadlineWithTwoMeasuresSecondEmpty } from "./fixturesData/HeadlineWithTwoMeasuresSecondEmpty.fixture.js"; +import { HeadlineWithTwoMeasuresSecondZero } from "./fixturesData/HeadlineWithTwoMeasuresSecondZero.fixture.js"; +import { PieChartWithMetricsOnly } from "./fixturesData/PieChartWithMetricsOnly.fixture.js"; +import { PieChartWithMetricsOnlyFundata } from "./fixturesData/PieChartWithMetricsOnlyFundata.fixture.js"; +import { ScatterPlotWith2MetricsAndAttributeNullsInData } from "./fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.fixture.js"; +import { type ILocalExecutionRecording, localDataView } from "./localDataView.fixture.js"; +import { recordedDataFacade } from "./recordings.fixture.js"; function localFixtureDataFacade(recording: ILocalExecutionRecording): DataViewFacade { return DataViewFacade.for(localDataView(recording)); diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/AreaChartWith3MetricsAndViewByAttribute.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/AreaChartWith3MetricsAndViewByAttribute.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/AreaChartWith3MetricsAndViewByAttribute.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/AreaChartWith3MetricsAndViewByAttribute.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttribute.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttribute.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttribute.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttribute.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributeFunformat.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith3MetricsAndViewByAttributePercInFormat.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWith4MetricsAndViewByTwoAttributes.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttribute.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttribute.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttribute.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttribute.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPopMeasureAndViewByAttributeX6.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPreviousPeriodMeasure.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPreviousPeriodMeasure.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPreviousPeriodMeasure.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPreviousPeriodMeasure.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPreviousPeriodMeasureX6.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPreviousPeriodMeasureX6.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BarChartWithPreviousPeriodMeasureX6.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BarChartWithPreviousPeriodMeasureX6.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/BubbleChartWith3MetricsAndAttributeNullsInData.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttribute.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttribute.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttribute.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttribute.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributeNoBuckets.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/ComboChartWithTwoMeasuresViewByAttributePercformat.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothEmpty.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothEmpty.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothEmpty.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothEmpty.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothSame.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothSame.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothSame.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothSame.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothZero.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothZero.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresBothZero.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresBothZero.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstEmpty.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstEmpty.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstEmpty.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstEmpty.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstZero.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstZero.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstZero.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresFirstZero.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondEmpty.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondEmpty.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondEmpty.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondEmpty.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondZero.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondZero.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondZero.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/HeadlineWithTwoMeasuresSecondZero.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/PieChartWithMetricsOnly.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/PieChartWithMetricsOnly.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/PieChartWithMetricsOnly.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/PieChartWithMetricsOnly.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/PieChartWithMetricsOnlyFundata.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/PieChartWithMetricsOnlyFundata.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/fixturesData/PieChartWithMetricsOnlyFundata.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/PieChartWithMetricsOnlyFundata.fixture.ts diff --git a/libs/sdk-ui-charts/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.ts b/libs/sdk-ui-charts/src/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.fixture.ts similarity index 99% rename from libs/sdk-ui-charts/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.ts rename to libs/sdk-ui-charts/src/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.fixture.ts index 6ede39098b9..1a0554642c9 100644 --- a/libs/sdk-ui-charts/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.ts +++ b/libs/sdk-ui-charts/src/testUtils/fixturesData/ScatterPlotWith2MetricsAndAttributeNullsInData.fixture.ts @@ -1,6 +1,6 @@ // (C) 2026 GoodData Corporation -import { type ILocalExecutionRecording } from "../localDataView.js"; +import { type ILocalExecutionRecording } from "../localDataView.fixture.js"; export const ScatterPlotWith2MetricsAndAttributeNullsInData = { definition: { diff --git a/libs/sdk-ui-charts/testUtils/localDataView.ts b/libs/sdk-ui-charts/src/testUtils/localDataView.fixture.ts similarity index 100% rename from libs/sdk-ui-charts/testUtils/localDataView.ts rename to libs/sdk-ui-charts/src/testUtils/localDataView.fixture.ts diff --git a/libs/sdk-ui-vis-commons/testUtils/recordings.ts b/libs/sdk-ui-charts/src/testUtils/recordings.fixture.ts similarity index 88% rename from libs/sdk-ui-vis-commons/testUtils/recordings.ts rename to libs/sdk-ui-charts/src/testUtils/recordings.fixture.ts index 9ec2c1f582f..d15b79efdd2 100644 --- a/libs/sdk-ui-vis-commons/testUtils/recordings.ts +++ b/libs/sdk-ui-charts/src/testUtils/recordings.fixture.ts @@ -1,4 +1,4 @@ -// (C) 2020 GoodData Corporation +// (C) 2020-2026 GoodData Corporation import { type ScenarioRecording, recordedDataView } from "@gooddata/sdk-backend-mockingbird"; import { DataViewFacade } from "@gooddata/sdk-ui"; diff --git a/libs/sdk-ui-charts/tsconfig.build.json b/libs/sdk-ui-charts/tsconfig.build.json index 3993a403cb3..63f3c80dd6b 100644 --- a/libs/sdk-ui-charts/tsconfig.build.json +++ b/libs/sdk-ui-charts/tsconfig.build.json @@ -5,8 +5,10 @@ "**/*.test.tsx", "**/*.fixture.ts", "**/*.fixtures.ts", + "**/*.test.helpers.ts", + "**/*.test.helpers.tsx", "**/test/helper.ts", - "**/MockProvider.ts", + "**/*.test.helpers.ts", "**/tests/*Mock.ts" ], "include": ["src/**/*"], diff --git a/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md b/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md index e33547b0d01..22504a22c56 100644 --- a/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md +++ b/libs/sdk-ui-dashboard/api/sdk-ui-dashboard.api.md @@ -179,6 +179,7 @@ import { ISettings } from '@gooddata/sdk-model'; import { IShareDialogInteractionData } from '@gooddata/sdk-ui-kit'; import { ISharedObject } from '@gooddata/sdk-ui-kit'; import { ISharingApplyPayload as ISharingApplyPayload_2 } from '@gooddata/sdk-ui-kit'; +import { ISlotProps } from '@gooddata/sdk-ui-kit'; import { ITableDataAttributeScope } from '@gooddata/sdk-ui'; import { ITempFilterContext } from '@gooddata/sdk-model'; import { ITheme } from '@gooddata/sdk-model'; @@ -2424,6 +2425,7 @@ export interface IAlertingDialogProps { // @alpha export interface IAlertingDialogSlots { + ActionBar?: ComponentType>; Destination?: ComponentType>; Filters?: ComponentType>; Header?: ComponentType>; @@ -2539,6 +2541,21 @@ export interface IAttributesDropdownProps extends IDashboardAttributeFilterPlace parameters?: IParameterDropdownListItem[]; } +// @alpha +export interface IAutomationDialogActionBarProps { + cancelButtonText: string; + deleteButtonText?: string; + helpLinkHref?: string; + helpLinkText?: string; + isSaving: boolean; + isSubmitDisabled: boolean; + onCancel: () => void; + onDelete?: () => void; + onSubmit: () => void; + submitButtonText: string; + submitButtonTooltipText?: string; +} + // @alpha export interface IAutomationDialogDestinationProps { notificationChannels: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; @@ -5775,7 +5792,9 @@ export interface IDateFiltersCustomizer { // @alpha export interface IDefaultAlertingDialogProps extends IAlertingDialogProps { + bottomContent?: ReactNode; slots?: IAlertingDialogSlots; + topContent?: ReactNode; } // @alpha (undocumented) @@ -5808,7 +5827,9 @@ export interface IDefaultDashboardToolbarGroupProps { // @alpha export interface IDefaultScheduledEmailDialogProps extends IScheduledEmailDialogProps { + bottomContent?: ReactNode; slots?: IScheduledEmailDialogSlots; + topContent?: ReactNode; } // @internal @@ -8073,6 +8094,7 @@ export interface IScheduledEmailDialogRecipientsProps extends IAutomationDialogR // @alpha export interface IScheduledEmailDialogSlots { + ActionBar?: ComponentType>; Destination?: ComponentType>; Filters?: ComponentType>; Header?: ComponentType>; @@ -9088,11 +9110,7 @@ export function isLayoutSectionPath(obj: unknown): obj is ILayoutSectionPath; // @internal export function isLoadingPlaceholderWidget(obj: unknown): obj is IPlaceholderWidget; -// @alpha -export interface ISlotProps { - Default: ComponentType; - defaultProps: TProps; -} +export { ISlotProps } // @internal (undocumented) export function isMeasureValueFilterDraggableItem(item: DraggableContentItem): item is MeasureValueFilterDraggableItem; diff --git a/libs/sdk-ui-dashboard/package.json b/libs/sdk-ui-dashboard/package.json index 8f8892e43bf..8ee64f897bb 100644 --- a/libs/sdk-ui-dashboard/package.json +++ b/libs/sdk-ui-dashboard/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-dashboard", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData SDK - Dashboard Component", "license": "LicenseRef-LICENSE", "author": "GoodData Corporation", diff --git a/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.fixture.ts b/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.fixture.ts rename to libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.ts b/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.ts index fdbd5becde0..27f2acfd8de 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dashboard/dashboardFilterContext.test.ts @@ -6,15 +6,18 @@ import { describe, expect, it } from "vitest"; import { uriRef } from "@gooddata/sdk-model"; -import { EmptyDashboardWithReferences } from "../../model/fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardWithReferences } from "../../model/fixtures/SimpleDashboard.fixtures.js"; +import { EmptyDashboardWithReferences } from "../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardWithReferences } from "../../tests/SimpleDashboard.test.helpers.js"; import { defaultDateFilterConfig } from "../dateFilterConfig/defaultConfig.js"; -import { TestFilterContext, TestFilterContextWithInvalidParents } from "./dashboardFilterContext.fixture.js"; import { dashboardFilterContextDefinition, dashboardFilterContextSanitize, } from "./dashboardFilterContext.js"; +import { + TestFilterContext, + TestFilterContextWithInvalidParents, +} from "./dashboardFilterContext.test.helpers.js"; // TODO RAIL-3383 move the fixtures? describe("dashboardFilterContextDefinition", () => { diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/fixtures.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfig.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/fixtures.ts rename to libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterConfig.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.test.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.test.ts index a960cc24ce6..4a1f30b3ebc 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.test.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/dateFilterOptionMapping.test.ts @@ -11,8 +11,8 @@ import { defaultDateFilterOptions, } from "@gooddata/sdk-ui-filters"; +import { allTime, last30days } from "./dateFilterConfig.test.helpers.js"; import { matchDateFilterToDateFilterOption } from "./dateFilterOptionMapping.js"; -import { allTime, last30days } from "./fixtures.js"; describe("matchDateFilterToDateFilterOption", () => { it.each< diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/merge.test.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/merge.test.ts index 372c422c7dc..cd04e58617d 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/merge.test.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/merge.test.ts @@ -14,7 +14,7 @@ import { lastYear, relativeForm, year2019, -} from "./fixtures.js"; +} from "./dateFilterConfig.test.helpers.js"; import { mergeDateFilterConfigs } from "./merge.js"; describe("mergeProjectConfigWithDashboardConfig", () => { diff --git a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/validation.test.ts b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/validation.test.ts index 4237f2ca13c..1d0d98e15a2 100644 --- a/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/validation.test.ts +++ b/libs/sdk-ui-dashboard/src/_staging/dateFilterConfig/validation.test.ts @@ -7,7 +7,14 @@ import { describe, expect, it } from "vitest"; import { type IDateFilterConfig, type ISettings, idRef } from "@gooddata/sdk-model"; import { suppressConsole } from "@gooddata/util"; -import { absoluteForm, allTime, emptyValues, lastMonth, relativeForm, year2019 } from "./fixtures.js"; +import { + absoluteForm, + allTime, + emptyValues, + lastMonth, + relativeForm, + year2019, +} from "./dateFilterConfig.test.helpers.js"; import { getValidDateFilterConfig, validateDateFilterConfig } from "./validation.js"; describe("validateDateFilterConfig", () => { diff --git a/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.mock.ts b/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/_staging/layout/coordinates.mock.ts rename to libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.ts b/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.ts index 5ce956bae58..d60ee306094 100644 --- a/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.ts +++ b/libs/sdk-ui-dashboard/src/_staging/layout/coordinates.test.ts @@ -30,7 +30,7 @@ import { updateItemIndex, updateSectionIndex, } from "./coordinates.js"; -import { NESTED_LAYOUT } from "./coordinates.mock.js"; +import { NESTED_LAYOUT } from "./coordinates.test.helpers.js"; describe("coordinates", () => { describe("areSameCoordinates", () => { diff --git a/libs/sdk-ui-dashboard/src/index.ts b/libs/sdk-ui-dashboard/src/index.ts index 51765c768c8..db113c7cb63 100644 --- a/libs/sdk-ui-dashboard/src/index.ts +++ b/libs/sdk-ui-dashboard/src/index.ts @@ -2250,12 +2250,13 @@ export type { IDefaultAlertingDialogProps, } from "./presentation/automations/alerting/types.js"; export type { + IAutomationDialogActionBarProps, IAutomationDialogDestinationProps, IAutomationDialogFiltersProps, IAutomationDialogHeaderProps, IAutomationDialogRecipientsProps, - ISlotProps, } from "./presentation/automations/shared/slots/types.js"; +export type { ISlotProps } from "@gooddata/sdk-ui-kit"; export type { IAutomationParameter } from "./presentation/automations/shared/automationFilters/automationParameters.js"; export { useAutomationsContext, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterLimitingItemsHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterLimitingItemsHandler.test.ts index 25cdb2d160b..6c38fe421af 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterLimitingItemsHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterLimitingItemsHandler.test.ts @@ -6,9 +6,9 @@ import { beforeEach, describe, expect, it } from "vitest"; import { idRef } from "@gooddata/sdk-model"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { setAttributeFilterLimitingItems } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../store/tabs/filterContext/filterContextSelectors.js"; const LIMITING_ITEM = idRef("my-metric", "measure"); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterModeHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterModeHandler.test.ts index 5e44e87d817..224a2e4aefd 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterModeHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeAttributeFilterModeHandler.test.ts @@ -4,9 +4,9 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { setDashboardAttributeFilterConfigMode } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectAttributeFilterConfigsOverrides } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js"; import { selectFilterContextAttributeFilters } from "../../store/tabs/filterContext/filterContextSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeSharingHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeSharingHandler.test.ts index 4488e599e94..ae5cca9dc9a 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeSharingHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/changeSharingHandler.test.ts @@ -4,12 +4,12 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IChangeSharing, changeSharing } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type DashboardSharingChanged } from "../../events/dashboard.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDashboardPermissions } from "../../store/dashboardPermissions/dashboardPermissionsSelectors.js"; import { dashboardPermissionsActions } from "../../store/dashboardPermissions/index.js"; import { selectDashboardShareStatus } from "../../store/meta/metaSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.test.ts index 3c5e7bbe768..f1a7875fb26 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.test.ts @@ -8,12 +8,18 @@ import { type IDashboardParameter, type IDashboardTab, type IParameterMetadataObject, + type ParameterValue, idRef, } from "@gooddata/sdk-model"; +import { type IDashboardParameterEntry } from "../../../store/tabs/parameters/parametersState.js"; import { DEFAULT_TAB_ID } from "../../../store/tabs/tabsState.js"; -import { distributeParametersToTabs } from "./parameterHydration.js"; +import { + distributeParametersToTabs, + hydrateParameterEntries, + resolveParameterValuesForFilterView, +} from "./parameterHydration.js"; const topNRef = idRef("topN", "parameter"); const sampleRef = idRef("sampleSize", "parameter"); @@ -137,3 +143,161 @@ describe("distributeParametersToTabs — activeTabOverride", () => { expect(distributed["tab-A"]).toEqual([{ parameter: topNParameter, runtimeOverride: 10 }]); }); }); + +const scenarioRef = idRef("scenario", "parameter"); + +const scenarioParameter: IDashboardParameter = { + ref: scenarioRef, + parameterType: "STRING", + mode: "active", +}; + +const sampleWorkspace: IParameterMetadataObject = { + ...topNWorkspace, + id: "sampleSize", + uri: "/sampleSize", + ref: sampleRef, + title: "Sample size", + definition: { type: "NUMBER", defaultValue: 6 }, +}; + +const scenarioWorkspace: IParameterMetadataObject = { + ...topNWorkspace, + id: "scenario", + uri: "/scenario", + ref: scenarioRef, + title: "Scenario", + definition: { type: "STRING", defaultValue: "Actual" }, +}; + +function entry(parameter: IDashboardParameter, runtimeOverride: ParameterValue | undefined = undefined) { + return { parameter, runtimeOverride } satisfies IDashboardParameterEntry; +} + +describe("resolveParameterValuesForFilterView", () => { + it("takes an explicit value from the filter view", () => { + expect( + resolveParameterValuesForFilterView( + [entry(topNParameter)], + [{ ...topNParameter, value: 42 }], + [topNWorkspace], + ), + ).toEqual([{ ref: topNRef, value: 42 }]); + }); + + it("fills a view parameter carrying no value from the workspace default", () => { + expect( + resolveParameterValuesForFilterView([entry(topNParameter)], [topNParameter], [topNWorkspace]), + ).toEqual([{ ref: topNRef, value: 10 }]); + }); + + it("fills a missing string value from the workspace string default", () => { + expect( + resolveParameterValuesForFilterView( + [entry(scenarioParameter)], + [scenarioParameter], + [scenarioWorkspace], + ), + ).toEqual([{ ref: scenarioRef, value: "Actual" }]); + }); + + it("leaves a view parameter unresolved when the workspace parameter is missing", () => { + expect(resolveParameterValuesForFilterView([entry(topNParameter)], [topNParameter], [])).toEqual([ + { ref: topNRef, value: undefined }, + ]); + }); + + it("leaves a view parameter unresolved when the workspace parameter type does not match", () => { + expect( + resolveParameterValuesForFilterView( + [entry(scenarioParameter)], + [scenarioParameter], + [{ ...scenarioWorkspace, definition: { type: "NUMBER", defaultValue: 10 } }], + ), + ).toEqual([{ ref: scenarioRef, value: undefined }]); + }); + + it("resets a parameter the view predates instead of keeping the previously applied value", () => { + // View saved with topN only; sampleSize was added later and still holds 4 from another view. + const values = resolveParameterValuesForFilterView( + [entry(topNParameter, 1), entry(sampleParameter, 4)], + [{ ...topNParameter, value: 1 }], + [topNWorkspace, sampleWorkspace], + ); + + expect(values).toEqual([ + { ref: topNRef, value: 1 }, + { ref: sampleRef, value: 6 }, + ]); + }); + + it("resets a parameter the view predates to the dashboard value when one is persisted", () => { + const pinned: IDashboardParameter = { ...sampleParameter, value: 3 }; + + expect( + resolveParameterValuesForFilterView( + [entry(pinned, 4)], + [{ ...topNParameter, value: 1 }], + [topNWorkspace, sampleWorkspace], + ), + ).toEqual([{ ref: sampleRef, value: 3 }]); + }); + + it("resets every parameter for a legacy view that captured none", () => { + expect( + resolveParameterValuesForFilterView( + [entry(topNParameter, 1), entry(sampleParameter, 4)], + [], + [topNWorkspace, sampleWorkspace], + ), + ).toEqual([ + { ref: topNRef, value: 10 }, + { ref: sampleRef, value: 6 }, + ]); + }); + + it("keeps the persisted value of a parameter the workspace no longer resolves", () => { + // Unlike a filter-bar reset, an unresolvable parameter is not cleared - the value stays + // whatever hydration produced at load, so the widget surfaces the standard error. + const removed: IDashboardParameter = { ...sampleParameter, value: 3 }; + + expect(resolveParameterValuesForFilterView([entry(removed, 4)], [], [])).toEqual([ + { ref: sampleRef, value: 3 }, + ]); + }); + + it("resolves a parameter the view omits exactly as load-time hydration would", () => { + const parameters = [topNParameter, { ...sampleParameter, value: 3 }, scenarioParameter]; + const workspaceParameters = [topNWorkspace, sampleWorkspace, scenarioWorkspace]; + + const resolved = resolveParameterValuesForFilterView( + hydrateParameterEntries(parameters, workspaceParameters), + [], + workspaceParameters, + ); + + expect(resolved).toEqual( + hydrateParameterEntries(parameters, workspaceParameters).map( + ({ parameter, runtimeOverride }) => ({ ref: parameter.ref, value: runtimeOverride }), + ), + ); + }); + + it("resolves entries the view omits regardless of their mode", () => { + const readonly: IDashboardParameter = { ...sampleParameter, mode: "readonly" }; + + expect( + resolveParameterValuesForFilterView([entry(readonly, 4)], [], [topNWorkspace, sampleWorkspace]), + ).toEqual([{ ref: sampleRef, value: 6 }]); + }); + + it("ignores view parameters that no longer exist on the tab", () => { + expect( + resolveParameterValuesForFilterView( + [entry(topNParameter, 1)], + [{ ...sampleParameter, value: 42 }], + [topNWorkspace, sampleWorkspace], + ), + ).toEqual([{ ref: topNRef, value: 10 }]); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.ts index 938e9f5c6fb..30fa5e1da85 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/parameterHydration.ts @@ -5,6 +5,7 @@ import { type IDashboardTab, type IParameterMetadataObject, type ParameterValue, + areObjRefsEqual, objRefToString, } from "@gooddata/sdk-model"; @@ -12,6 +13,7 @@ import { buildWorkspaceParametersByRef, computeHydratedRuntimeOverride, } from "../../../store/tabs/parameters/parametersHelpers.js"; +import { type ISetParameterRuntimeValuePayload } from "../../../store/tabs/parameters/parametersReducers.js"; import { type IDashboardParameterEntry, pickTabParametersSource, @@ -76,6 +78,30 @@ export function distributeParametersToTabs( return result; } +/** + * A filter view holds only the parameters that existed when the user saved it. A parameter that the + * view omits gets the same value that {@link hydrateParameterEntries} gave it at load time. No value + * from an earlier view stays applied. + */ +export function resolveParameterValuesForFilterView( + entries: ReadonlyArray, + filterViewParameters: ReadonlyArray, + workspaceParameters: IParameterMetadataObject[], +): ISetParameterRuntimeValuePayload[] { + const workspaceByRef = buildWorkspaceParametersByRef(workspaceParameters); + return entries.map((entry) => { + const { ref } = entry.parameter; + const fromView = filterViewParameters.find((item) => areObjRefsEqual(item.ref, ref)); + return { + ref, + value: computeHydratedRuntimeOverride( + fromView ?? entry.parameter, + workspaceByRef.get(objRefToString(ref)), + ), + }; + }); +} + function applyRuntimeOverrides( entries: IDashboardParameterEntry[], overrides: IDashboardParameter[], diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/deleteDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/deleteDashboardHandler.test.ts index 9013e18ccd5..88c813ce803 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/deleteDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/deleteDashboardHandler.test.ts @@ -4,12 +4,12 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { deleteDashboard } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardDeleted } from "../../events/dashboard.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDateFilterConfig } from "../../store/config/configSelectors.js"; import { selectInsights } from "../../store/insights/insightsSelectors.js"; import { selectDashboardTitle, selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/exportDashboardToPdfHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/exportDashboardToPdfHandler.test.ts index ae7f70a78e7..1d38fbda0dd 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/exportDashboardToPdfHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/exportDashboardToPdfHandler.test.ts @@ -16,6 +16,7 @@ import { } from "@gooddata/sdk-backend-spi"; import { type FilterContextItem, type ObjRef, idRef } from "@gooddata/sdk-model"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { exportDashboardToPdf, exportDashboardToPdfPresentation, @@ -24,7 +25,6 @@ import { } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardExportToPdfResolved } from "../../events/dashboard.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { HeadlessDashboard } from "../../headlessDashboard/HeadlessDashboard.js"; import { type DashboardContext } from "../../types/commonTypes.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/initializeDashboardHandler/handler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/initializeDashboardHandler/handler.test.ts index 607747c5e84..c45d52a6a8e 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/initializeDashboardHandler/handler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/initializeDashboardHandler/handler.test.ts @@ -8,15 +8,15 @@ import { type IDashboard, idRef } from "@gooddata/sdk-model"; import { createDefaultFilterContext } from "../../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../../_staging/dateFilterConfig/defaultConfig.js"; -import { initializeDashboard } from "../../../commands/dashboard.js"; -import { DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { type DashboardInitialized } from "../../../events/dashboard.js"; import { EmptyDashboardIdentifier, EmptyDashboardWithReferences, TestCorrelation, -} from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; +} from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; +import { initializeDashboard } from "../../../commands/dashboard.js"; +import { DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; +import { type DashboardInitialized } from "../../../events/dashboard.js"; import { selectConfig } from "../../../store/config/configSelectors.js"; import { selectPersistedDashboard } from "../../../store/meta/metaSelectors.js"; import { selectPermissions } from "../../../store/permissions/permissionsSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/renameDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/renameDashboardHandler.test.ts index d1a5e3815c4..483b1952fbe 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/renameDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/renameDashboardHandler.test.ts @@ -4,11 +4,11 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { renameDashboard } from "../../commands/dashboard.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardRenamed } from "../../events/dashboard.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDashboardTitle, selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; describe("rename dashboard handler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/resetDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/resetDashboardHandler.test.ts index 00b511e2f0b..2c796713a6f 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/resetDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/resetDashboardHandler.test.ts @@ -7,17 +7,17 @@ import { beforeEach, describe, expect, it } from "vitest"; import { ReferenceMd } from "@gooddata/reference-workspace"; import { attributeDisplayFormRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { + SimpleDashboardFilterContext, + SimpleDashboardIdentifier, + SimpleDashboardLayout, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { renameDashboard, resetDashboard } from "../../commands/dashboard.js"; import { addAttributeFilter } from "../../commands/filters.js"; import { addLayoutSection } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardWasReset } from "../../events/dashboard.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { - SimpleDashboardFilterContext, - SimpleDashboardIdentifier, - SimpleDashboardLayout, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDashboardTitle } from "../../store/meta/metaSelectors.js"; import { selectFilterContextAttributeFilters, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveAsDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveAsDashboardHandler.test.ts index c7039bf529c..9e69391072c 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveAsDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveAsDashboardHandler.test.ts @@ -2,16 +2,16 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { saveDashboard, saveDashboardAs } from "../../commands/dashboard.js"; import { addLayoutSection } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type DashboardCopySaved, type DashboardSaved } from "../../events/dashboard.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { TestInsightItem } from "../../fixtures/Layout.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDashboardTitle, selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; import { selectFilterContextIdentity } from "../../store/tabs/filterContext/filterContextSelectors.js"; import { selectBasicLayout } from "../../store/tabs/layout/layoutSelectors.js"; +import { TestInsightItem } from "../../tests/Layout.test.helpers.js"; import { isTemporaryIdentity } from "../../utils/dashboardItemUtils.js"; describe("save as dashboard handler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts index ffa1ad8afb1..195ecb3ff79 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/saveDashboardHandler.test.ts @@ -4,19 +4,19 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type IDashboardDefinition } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { + SimpleDashboardFilterContext, + SimpleDashboardWithReferences, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { saveDashboard } from "../../commands/dashboard.js"; import { addLayoutSection } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type DashboardSaved } from "../../events/dashboard.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { TestInsightItem } from "../../fixtures/Layout.fixtures.js"; -import { - SimpleDashboardFilterContext, - SimpleDashboardWithReferences, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectPersistedDashboard } from "../../store/meta/metaSelectors.js"; import { selectFilterContextIdentity } from "../../store/tabs/filterContext/filterContextSelectors.js"; import { selectBasicLayout } from "../../store/tabs/layout/layoutSelectors.js"; +import { TestInsightItem } from "../../tests/Layout.test.helpers.js"; import { isTemporaryIdentity } from "../../utils/dashboardItemUtils.js"; import { getDashboardWithSharing } from "./saveDashboardHandler.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/drillToDashboardHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/drillToDashboardHandler.test.ts index fe8c4dbf4b7..b4d45cf3db3 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/drillToDashboardHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/drill/drillToDashboardHandler.test.ts @@ -4,14 +4,14 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type IDashboardParameter, type IDrillToDashboard, idRef } from "@gooddata/sdk-model"; +import { + SimpleDashboardIdentifier, + SimpleSortedTableWidgetRef, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IDashboardDrillEvent } from "../../../types.js"; import { drillToDashboard } from "../../commands/drill.js"; import { createDashboardTab, switchDashboardTab } from "../../commands/tabs.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { - SimpleDashboardIdentifier, - SimpleSortedTableWidgetRef, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { tabsActions } from "../../store/tabs/index.js"; import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/drillTargets/addDrillTargetsHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/drillTargets/addDrillTargetsHandler.test.ts index 1cf0928d4dd..4774da1cdbb 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/drillTargets/addDrillTargetsHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/drillTargets/addDrillTargetsHandler.test.ts @@ -7,16 +7,16 @@ import { beforeEach, describe, expect, it } from "vitest"; import { uriRef } from "@gooddata/sdk-model"; import { type IAvailableDrillTargets } from "@gooddata/sdk-ui"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { + SimpleDashboardIdentifier, + SimpleSortedTableWidgetRef, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IAddDrillTargets, addDrillTargets } from "../../commands/drillTargets.js"; import { changeRenderMode } from "../../commands/renderMode.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDrillTargetsAdded } from "../../events/drillTargets.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { - SimpleDashboardIdentifier, - SimpleSortedTableWidgetRef, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectDrillTargetsByWidgetRef } from "../../store/drillTargets/drillTargetsSelectors.js"; import { selectInvalidDrillWidgetRefs } from "../../store/ui/uiSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.test.ts index 468dfe60f14..9bf06e2b04d 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.test.ts @@ -7,11 +7,11 @@ import { beforeEach, describe, expect, it } from "vitest"; import { ReferenceMd } from "@gooddata/reference-workspace"; import { DashboardAttributeFilterConfigModeValues, uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { addAttributeFilter } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../../events/general.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectAttributeFilterConfigsModeMap } from "../../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js"; import { selectAttributeFilterDisplayFormsMap, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.test.ts index cf7880a4e8d..1cd0431ff31 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.test.ts @@ -11,10 +11,10 @@ import { isDashboardMatchAttributeFilter, } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { addTextAttributeFilter } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilterItemByDisplayForm } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("addTextAttributeFilterHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.test.ts index 2a1555da31d..a73eb8755e0 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.test.ts @@ -4,10 +4,10 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { changeAttributeFilterSelection, setAttributeFilterParents } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("changeAttributeFilterSelectionHandler.test", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeSelectionModeHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeSelectionModeHandler.test.ts index 434fbeb5e1a..43381b35478 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeSelectionModeHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeSelectionModeHandler.test.ts @@ -4,9 +4,9 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { setAttributeFilterSelectionMode } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("changeAttributeSelectionModeHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeTitleHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeTitleHandler.test.ts index 3a0a810459d..55926d2a910 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeTitleHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/changeAttributeTitleHandler.test.ts @@ -4,10 +4,10 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { setAttributeFilterTitle } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("changeAttributeTitleHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/moveAttributeFilterHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/moveAttributeFilterHandler.test.ts index dc8e35fc7dd..d81051d83da 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/moveAttributeFilterHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/moveAttributeFilterHandler.test.ts @@ -4,10 +4,10 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { moveAttributeFilter } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("moveAttributeFilterHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFilterHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFilterHandler.test.ts index a994723f453..47d532fce10 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFilterHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/removeAttributeFilterHandler.test.ts @@ -4,10 +4,10 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { removeAttributeFilter } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectAttributeFilterDisplayFormsMap, selectFilterContextAttributeFilters, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/setAttributeFilterParentHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/setAttributeFilterParentHandler.test.ts index 3258fe9fe20..eefeb61e891 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/setAttributeFilterParentHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/setAttributeFilterParentHandler.test.ts @@ -6,9 +6,9 @@ import { beforeEach, describe, expect, it } from "vitest"; import { idRef } from "@gooddata/sdk-model"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { setAttributeFilterParents } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextAttributeFilters } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("setAttributeFilterParentHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/validation/parentFiltersValidation.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/validation/parentFiltersValidation.test.ts index 646883a332e..8d8b8082dcd 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/validation/parentFiltersValidation.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/attributeFilter/validation/parentFiltersValidation.test.ts @@ -14,7 +14,7 @@ import { } from "@gooddata/sdk-model"; import { type ObjRefMap, newDisplayFormMap } from "../../../../../_staging/metadata/objRefMap.js"; -import { SimpleDashboardIdentifier } from "../../../../fixtures/SimpleDashboard.fixtures.js"; +import { SimpleDashboardIdentifier } from "../../../../../tests/SimpleDashboard.test.helpers.js"; import { type DashboardContext } from "../../../../types/commonTypes.js"; import { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.test.ts index 5a1ea96ec01..37c09f4a875 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.test.ts @@ -19,6 +19,10 @@ import { import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../_staging/dateFilterConfig/defaultConfig.js"; +import { + EmptyDashboardIdentifier, + EmptyDashboardWithReferences, +} from "../../../tests/Dashboard.test.helpers.js"; import { addAttributeFilter, addTextAttributeFilter, @@ -27,7 +31,6 @@ import { removeAttributeFilter, } from "../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { EmptyDashboardIdentifier, EmptyDashboardWithReferences } from "../../fixtures/Dashboard.fixtures.js"; import { selectFilterContextAttributeFilterItemByDisplayForm, selectFilterContextAttributeFilterItemByLocalId, diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.test.ts index eec5d19f459..5215919b286 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.test.ts @@ -4,10 +4,10 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { changeDateFilterSelection, clearDateFilterSelection } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectFilterContextDateFilter } from "../../../store/tabs/filterContext/filterContextSelectors.js"; describe("changeDateFilterSelectionHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewHandler.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewHandler.ts index 9da1e902b2c..75a140f1941 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewHandler.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewHandler.ts @@ -42,14 +42,17 @@ import { selectWorkingFilterContextDefinition, } from "../../store/tabs/filterContext/filterContextSelectors.js"; import { tabsActions } from "../../store/tabs/index.js"; -import { selectFilterViewParameters } from "../../store/tabs/parameters/parametersSelectors.js"; +import { + selectDashboardParameterEntries, + selectFilterViewParameters, +} from "../../store/tabs/parameters/parametersSelectors.js"; import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js"; import { type DashboardContext } from "../../types/commonTypes.js"; import { type PromiseFnReturnType } from "../../types/sagas.js"; +import { resolveParameterValuesForFilterView } from "../dashboard/common/parameterHydration.js"; import { loadFilterViews } from "../dashboard/initializeDashboardHandler/loadFilterViews.js"; import { resetCrossFiltering } from "./common.js"; -import { resolveFilterViewParameterValues } from "./filterViewParameters.js"; function createFilterView( ctx: DashboardContext, @@ -190,12 +193,20 @@ export function* applyFilterViewHandler(ctx: DashboardContext, cmd: IApplyFilter matchByLocalIdentifier: true, }), ); - if (filterView.parameters && filterView.parameters.length > 0) { - const workspaceParameters: ReturnType = - yield select(selectCatalogParameters); - const values = resolveFilterViewParameterValues(filterView.parameters, workspaceParameters); - yield put(tabsActions.setParameterRuntimeValues({ values })); - } + const parameterEntries: ReturnType = yield select( + selectDashboardParameterEntries, + ); + const workspaceParameters: ReturnType = + yield select(selectCatalogParameters); + yield put( + tabsActions.setParameterRuntimeValues({ + values: resolveParameterValuesForFilterView( + parameterEntries, + filterView.parameters ?? [], + workspaceParameters, + ), + }), + ); yield put(filterViewApplicationSucceeded(ctx, filterView, cmd.correlationId)); } else { yield put(filterViewApplicationFailed(ctx)); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.test.ts deleted file mode 100644 index 869f7c949c1..00000000000 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -// (C) 2026 GoodData Corporation - -// @vitest-environment node - -import { describe, expect, it } from "vitest"; - -import { type IDashboardParameter, type IParameterMetadataObject, idRef } from "@gooddata/sdk-model"; - -import { resolveFilterViewParameterValues } from "./filterViewParameters.js"; - -const topNParameter: IDashboardParameter = { - ref: idRef("topN", "parameter"), - parameterType: "NUMBER", - mode: "active", -}; - -describe("resolveFilterViewParameterValues", () => { - const workspaceParameter: IParameterMetadataObject = { - type: "parameter", - id: "topN", - uri: "/topN", - ref: topNParameter.ref, - title: "Top N", - description: "", - production: true, - deprecated: false, - unlisted: false, - definition: { type: "NUMBER", defaultValue: 10 }, - }; - - it("preserves explicit values from the filter view", () => { - expect( - resolveFilterViewParameterValues([{ ...topNParameter, value: 42 }], [workspaceParameter]), - ).toEqual([{ ref: topNParameter.ref, value: 42 }]); - }); - - it("fills missing values from the workspace default", () => { - expect(resolveFilterViewParameterValues([topNParameter], [workspaceParameter])).toEqual([ - { ref: topNParameter.ref, value: 10 }, - ]); - }); - - it("keeps missing values unresolved when workspace default is unavailable", () => { - expect(resolveFilterViewParameterValues([topNParameter], [])).toEqual([ - { ref: topNParameter.ref, value: undefined }, - ]); - }); - - const scenarioParameter: IDashboardParameter = { - ref: idRef("scenario", "parameter"), - parameterType: "STRING", - mode: "active", - }; - - const scenarioWorkspaceParameter: IParameterMetadataObject = { - type: "parameter", - id: "scenario", - uri: "/scenario", - ref: scenarioParameter.ref, - title: "Scenario", - description: "", - production: true, - deprecated: false, - unlisted: false, - definition: { type: "STRING", defaultValue: "Actual" }, - }; - - it("fills a missing string value from the workspace string default", () => { - expect(resolveFilterViewParameterValues([scenarioParameter], [scenarioWorkspaceParameter])).toEqual([ - { ref: scenarioParameter.ref, value: "Actual" }, - ]); - }); - - it("keeps a missing value unresolved when the workspace parameter type does not match", () => { - const numberTypedWorkspaceParameter: IParameterMetadataObject = { - ...scenarioWorkspaceParameter, - definition: { type: "NUMBER", defaultValue: 10 }, - }; - expect( - resolveFilterViewParameterValues([scenarioParameter], [numberTypedWorkspaceParameter]), - ).toEqual([{ ref: scenarioParameter.ref, value: undefined }]); - }); -}); diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.ts deleted file mode 100644 index 317180d9690..00000000000 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/filterViewParameters.ts +++ /dev/null @@ -1,29 +0,0 @@ -// (C) 2026 GoodData Corporation - -import { - type IDashboardParameter, - type IParameterMetadataObject, - type ObjRef, - type ParameterValue, - areObjRefsEqual, -} from "@gooddata/sdk-model"; - -import { computeHydratedRuntimeOverride } from "../../store/tabs/parameters/parametersHelpers.js"; - -interface IResolvedFilterViewParameter { - ref: ObjRef; - value: ParameterValue | undefined; -} - -export function resolveFilterViewParameterValues( - parameters: ReadonlyArray, - workspaceParameters: ReadonlyArray, -): IResolvedFilterViewParameter[] { - return parameters.map((parameter) => ({ - ref: parameter.ref, - value: computeHydratedRuntimeOverride( - parameter, - workspaceParameters.find((item) => areObjRefsEqual(item.ref, parameter.ref)), - ), - })); -} diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/measureValueFilter/addMeasureValueFilterHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/measureValueFilter/addMeasureValueFilterHandler.test.ts index 910324568c8..689a30781d1 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/measureValueFilter/addMeasureValueFilterHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/filterContext/measureValueFilter/addMeasureValueFilterHandler.test.ts @@ -6,11 +6,11 @@ import { beforeEach, describe, expect, it } from "vitest"; import { DashboardAttributeFilterConfigModeValues, idRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../../tests/SimpleDashboard.test.helpers.js"; import { addMeasureValueFilter } from "../../../commands/filters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../../events/general.js"; -import { TestCorrelation } from "../../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../../fixtures/SimpleDashboard.fixtures.js"; import { selectMeasureValueFilterConfigsModeMap } from "../../../store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js"; describe("addMeasureValueFilterHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addLayoutSectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addLayoutSectionHandler.test.ts index 15ab3d4a8e3..b071a1ca507 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addLayoutSectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addLayoutSectionHandler.test.ts @@ -8,17 +8,20 @@ import { type IAnalyticalWidget, type IDashboard, idRef, uriRef } from "@gooddat import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../_staging/dateFilterConfig/defaultConfig.js"; -import { type IAddLayoutSection, addLayoutSection, undoLayoutChanges } from "../../commands/layout.js"; -import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { type IDashboardCommandFailed } from "../../events/general.js"; -import { type IDashboardLayoutChanged, type IDashboardLayoutSectionAdded } from "../../events/layout.js"; -import { ActivityDateDatasetRef } from "../../fixtures/CatalogAvailability.fixtures.js"; import { EmptyDashboardIdentifier, EmptyDashboardWithReferences, TestCorrelation, TestStash, -} from "../../fixtures/Dashboard.fixtures.js"; +} from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; +import { type IAddLayoutSection, addLayoutSection, undoLayoutChanges } from "../../commands/layout.js"; +import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; +import { type IDashboardCommandFailed } from "../../events/general.js"; +import { type IDashboardLayoutChanged, type IDashboardLayoutSectionAdded } from "../../events/layout.js"; +import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +import { ActivityDateDatasetRef } from "../../tests/CatalogAvailability.test.helpers.js"; import { TestInsightItem, TestInsightPlaceholderItem, @@ -28,10 +31,7 @@ import { createTestInsightItem, testItemWithDateDataset, testItemWithFilterIgnoreList, -} from "../../fixtures/Layout.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/Layout.test.helpers.js"; import { type PrivateDashboardContext } from "../../types/commonTypes.js"; import { EmptyDashboardLayout } from "../dashboard/common/dashboardInitialize.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addSectionItemsHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addSectionItemsHandler.test.ts index 58c08b7fed5..09095256536 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addSectionItemsHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/addSectionItemsHandler.test.ts @@ -6,21 +6,21 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation, TestStash } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IAddSectionItems, addSectionItem, undoLayoutChanges } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardLayoutSectionItemsAdded } from "../../events/layout.js"; -import { ComplexDashboardIdentifier } from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation, TestStash } from "../../fixtures/Dashboard.fixtures.js"; +import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; +import { selectLayout, selectUndoableLayoutCommands } from "../../store/tabs/layout/layoutSelectors.js"; +import { ComplexDashboardIdentifier } from "../../tests/ComplexDashboard.test.helpers.js"; import { TestInsightItem, TestInsightPlaceholderItem, TestKpiPlaceholderItem, createTestInsightItem, -} from "../../fixtures/Layout.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; -import { selectLayout, selectUndoableLayoutCommands } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/Layout.test.helpers.js"; /* * Bootstrapping a dashboard tester (recorded backend + store + the whole InitializeDashboard flow) is by far the diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/changeLayoutSectionHeaderHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/changeLayoutSectionHeaderHandler.test.ts index 64890a73bc5..f75b3b3afe5 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/changeLayoutSectionHeaderHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/changeLayoutSectionHeaderHandler.test.ts @@ -4,6 +4,8 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type ChangeLayoutSectionHeader, changeLayoutSectionHeader, @@ -15,8 +17,6 @@ import { type IDashboardLayoutChanged, type IDashboardLayoutSectionHeaderChanged, } from "../../events/layout.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; const FullHeader = { title: "My Section", description: "My Section Description" }; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveLayoutSectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveLayoutSectionHandler.test.ts index 8a94d488a2b..8088ed239b3 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveLayoutSectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveLayoutSectionHandler.test.ts @@ -4,17 +4,17 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IMoveLayoutSection, moveLayoutSection, undoLayoutChanges } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardLayoutChanged, type IDashboardLayoutSectionMoved } from "../../events/layout.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("move section command handler", () => { describe("for any dashboard", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemHandler.test.ts index 60336e06b17..67186b2831d 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemHandler.test.ts @@ -4,6 +4,8 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type ILayoutItemPath } from "../../../types.js"; import { type IMoveLayoutSection, @@ -14,13 +16,11 @@ import { import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardLayoutChanged, type IDashboardLayoutSectionItemMoved } from "../../events/layout.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; import { getSectionPathWithItemsShifted } from "./moveSectionItemHandler.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemToNewSectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemToNewSectionHandler.test.ts index 8242572f1ed..7d476e9a868 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemToNewSectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/moveSectionItemToNewSectionHandler.test.ts @@ -4,6 +4,8 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IMoveLayoutSection, moveSectionItemToNewSection, @@ -13,13 +15,11 @@ import { import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardLayoutChanged, type IDashboardLayoutSectionItemMoved } from "../../events/layout.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("move layout section item to new section handler", () => { describe("for any dashboard", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeLayoutSectionHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeLayoutSectionHandler.test.ts index bed7445efc8..c4876efd266 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeLayoutSectionHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeLayoutSectionHandler.test.ts @@ -8,17 +8,17 @@ import { type IDashboard, idRef } from "@gooddata/sdk-model"; import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../_staging/dateFilterConfig/defaultConfig.js"; -import { type IRemoveLayoutSection, removeLayoutSection, undoLayoutChanges } from "../../commands/layout.js"; -import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { type IDashboardCommandFailed } from "../../events/general.js"; -import { type IDashboardLayoutChanged, type IDashboardLayoutSectionRemoved } from "../../events/layout.js"; import { EmptyDashboardIdentifier, EmptyDashboardWithReferences, TestCorrelation, TestStash, -} from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; +} from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; +import { type IRemoveLayoutSection, removeLayoutSection, undoLayoutChanges } from "../../commands/layout.js"; +import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; +import { type IDashboardCommandFailed } from "../../events/general.js"; +import { type IDashboardLayoutChanged, type IDashboardLayoutSectionRemoved } from "../../events/layout.js"; import { selectLayout, selectStash } from "../../store/tabs/layout/layoutSelectors.js"; import { type PrivateDashboardContext } from "../../types/commonTypes.js"; import { EmptyDashboardLayout } from "../dashboard/common/dashboardInitialize.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemByWidgetRefHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemByWidgetRefHandler.test.ts index 1724c52f7b4..719c2dc7bc1 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemByWidgetRefHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemByWidgetRefHandler.test.ts @@ -6,6 +6,8 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type ObjRef, idRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IRemoveSectionItemByWidgetRef, eagerRemoveSectionItemByWidgetRef, @@ -19,14 +21,12 @@ import { type IDashboardLayoutSectionItemRemoved, type IDashboardLayoutSectionRemoved, } from "../../events/layout.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardLayout, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("remove layout section item handler", () => { describe("for any dashboard", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemHandler.test.ts index a7e8d5160c9..d20bd70c9d3 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/removeSectionItemHandler.test.ts @@ -4,6 +4,8 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation, TestStash } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IRemoveSectionItem, eagerRemoveSectionItem, @@ -17,14 +19,12 @@ import { type IDashboardLayoutSectionItemRemoved, type IDashboardLayoutSectionRemoved, } from "../../events/layout.js"; +import { selectLayout, selectStash } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardLayout, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation, TestStash } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectLayout, selectStash } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("remove layout section item handler", () => { describe("for any dashboard", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/replaceSectionItemHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/replaceSectionItemHandler.test.ts index 9f6010f642f..a3e077b3064 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/replaceSectionItemHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/replaceSectionItemHandler.test.ts @@ -6,6 +6,8 @@ import { beforeEach, describe, expect, it } from "vitest"; import { uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation, TestStash } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IReplaceSectionItem, replaceSectionItem, undoLayoutChanges } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; @@ -13,20 +15,18 @@ import { type IDashboardLayoutChanged, type IDashboardLayoutSectionItemReplaced, } from "../../events/layout.js"; +import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; +import { selectLayout, selectStash } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation, TestStash } from "../../fixtures/Dashboard.fixtures.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; import { TestInsightItem, TestKpiPlaceholderItem, testItemWithDateDataset, testItemWithFilterIgnoreList, -} from "../../fixtures/Layout.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; -import { selectInsightByRef } from "../../store/insights/insightsSelectors.js"; -import { selectLayout, selectStash } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/Layout.test.helpers.js"; describe("replace section item handler", () => { describe("for any dashboard", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeHeightHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeHeightHandler.test.ts index 1798774d6ce..0f3d84d0c80 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeHeightHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeHeightHandler.test.ts @@ -4,11 +4,11 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IResizeHeight, resizeHeight } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; describe("resize section items height handler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeWidthHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeWidthHandler.test.ts index b51a54eceec..651dd9ff676 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeWidthHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/resizeWidthHandler.test.ts @@ -4,11 +4,11 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IResizeWidth, resizeWidth } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; describe("resize section items width handler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/stashing.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/stashing.test.ts index 727d96a69ec..f8feaaf71f8 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/stashing.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/layout/stashing.test.ts @@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestStash } from "../../../tests/Dashboard.test.helpers.js"; import { addLayoutSection, addSectionItem, @@ -12,13 +13,12 @@ import { replaceSectionItem, } from "../../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; +import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWithReferences, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestStash } from "../../fixtures/Dashboard.fixtures.js"; -import { TestKpiPlaceholderItem } from "../../fixtures/Layout.fixtures.js"; -import { selectLayout } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; +import { TestKpiPlaceholderItem } from "../../tests/Layout.test.helpers.js"; describe("stashing", () => { let Tester: DashboardTester; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/parameters/changeParameterValuesHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/parameters/changeParameterValuesHandler.test.ts index 3cad2732e5c..ade2e0e7d8c 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/parameters/changeParameterValuesHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/parameters/changeParameterValuesHandler.test.ts @@ -6,9 +6,9 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type IDashboardParameter, idRef } from "@gooddata/sdk-model"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { changeParameterValues } from "../../commands/parameters.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { tabsActions } from "../../store/tabs/index.js"; import { selectParameterRuntimeOverrideByRef } from "../../store/tabs/parameters/parametersSelectors.js"; import { selectActiveTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/render/renderingWorker.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/render/renderingWorker.test.ts index 452a3560008..651516e8918 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/render/renderingWorker.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/render/renderingWorker.test.ts @@ -8,10 +8,13 @@ import { type IDashboard, idRef } from "@gooddata/sdk-model"; import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../_staging/dateFilterConfig/defaultConfig.js"; +import { + EmptyDashboardIdentifier, + EmptyDashboardWithReferences, +} from "../../../tests/Dashboard.test.helpers.js"; import { initializeDashboard } from "../../commands/dashboard.js"; import { requestAsyncRender, resolveAsyncRender } from "../../commands/render.js"; import { DashboardTester } from "../../DashboardTester.js"; -import { EmptyDashboardIdentifier, EmptyDashboardWithReferences } from "../../fixtures/Dashboard.fixtures.js"; import { type PrivateDashboardContext } from "../../types/commonTypes.js"; import { EmptyDashboardLayout } from "../dashboard/common/dashboardInitialize.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/renderMode/changeRenderModeHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/renderMode/changeRenderModeHandler.test.ts index 6e6e92a6bfb..d6d02782d26 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/renderMode/changeRenderModeHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/renderMode/changeRenderModeHandler.test.ts @@ -4,14 +4,14 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; import { initializeDashboard } from "../../commands/dashboard.js"; import { cancelEditRenderMode, changeRenderMode, switchToEditRenderMode } from "../../commands/renderMode.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardNoDrillsIdentifier } from "../../fixtures/SimpleDashboardNoDrills.fixtures.js"; import { selectRenderMode } from "../../store/renderMode/renderModeSelectors.js"; import { uiActions } from "../../store/ui/index.js"; import { selectTimezoneOverride } from "../../store/ui/uiSelectors.js"; +import { SimpleDashboardNoDrillsIdentifier } from "../tests/SimpleDashboardNoDrills.test.helpers.js"; describe("changeRenderModeHandler", () => { let Tester: DashboardTester; diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/SimpleDashboardNoDrills.fixtures.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/tests/SimpleDashboardNoDrills.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/fixtures/SimpleDashboardNoDrills.fixtures.ts rename to libs/sdk-ui-dashboard/src/model/commandHandlers/tests/SimpleDashboardNoDrills.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.test.ts index c40ccdc7b0a..ceb12839ec8 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/timezone/changeDashboardTimezoneOverrideHandler.test.ts @@ -6,15 +6,15 @@ import { beforeEach, describe, expect, it } from "vitest"; import { BROWSER_DETECTED } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; import { initializeDashboard } from "../../commands/dashboard.js"; import { changeDashboardTimezoneOverride } from "../../commands/timezone.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardTimezoneOverrideChanged } from "../../events/timezone.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { SimpleDashboardNoDrillsIdentifier } from "../../fixtures/SimpleDashboardNoDrills.fixtures.js"; import { metaActions } from "../../store/meta/index.js"; import { selectEffectiveDashboardTimezone } from "../../store/meta/metaSelectors.js"; import { selectTimezoneOverride } from "../../store/ui/uiSelectors.js"; +import { SimpleDashboardNoDrillsIdentifier } from "../tests/SimpleDashboardNoDrills.test.helpers.js"; async function createTester(enableTimezoneChange: boolean): Promise { let Tester: DashboardTester; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetHeaderHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetHeaderHandler.test.ts index 331c13505d4..410e9f6cc12 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetHeaderHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetHeaderHandler.test.ts @@ -4,16 +4,16 @@ import { beforeEach, describe, expect, it } from "vitest"; import { idRef, uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; import { type IChangeInsightWidgetHeader, changeInsightWidgetHeader } from "../../commands/insight.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardInsightWidgetHeaderChanged } from "../../events/insight.js"; +import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWidgets, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("change insight widget header handler", () => { describe("for dashboard with KPIs and insights", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetInsightHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetInsightHandler.test.ts index 0aabfe489b2..6b572b0f7ec 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetInsightHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetInsightHandler.test.ts @@ -4,17 +4,17 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type IInsightWidget, insightRef, uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { + SimpleDashboardIdentifier, + SimpleSortedTableWidgetRef, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { type IChangeInsightWidgetInsight, changeInsightWidgetInsight } from "../../commands/insight.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardInsightWidgetInsightSwitched } from "../../events/insight.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { PivotTableWithRowAndColumnAttributes } from "../../fixtures/Insights.fixtures.js"; -import { - SimpleDashboardIdentifier, - SimpleSortedTableWidgetRef, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; +import { PivotTableWithRowAndColumnAttributes } from "../../tests/Insights.test.helpers.js"; describe("change insight widget vis properties handler", () => { let Tester: DashboardTester; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetVisPropertiesHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetVisPropertiesHandler.test.ts index 3c979c168b0..2ff01fd2bf8 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetVisPropertiesHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeInsightWidgetVisPropertiesHandler.test.ts @@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it } from "vitest"; import { type IInsightWidget, idRef, uriRef } from "@gooddata/sdk-model"; +import { TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; import { type IChangeInsightWidgetVisProperties, changeInsightWidgetVisProperties, @@ -11,12 +12,11 @@ import { import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardInsightWidgetVisPropertiesChanged } from "../../events/insight.js"; +import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; import { ComplexDashboardIdentifier, ComplexDashboardWidgets, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; describe("change insight widget vis properties handler", () => { describe("for dashboard with KPIs and insights", () => { diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeRichTextWidgetContentHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeRichTextWidgetContentHandler.test.ts index dc96e7b3379..eedd6992375 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeRichTextWidgetContentHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeRichTextWidgetContentHandler.test.ts @@ -6,18 +6,18 @@ import { type IDashboard, type IRichTextWidgetDefinition, idRef } from "@gooddat import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../../_staging/dateFilterConfig/defaultConfig.js"; +import { + EmptyDashboardIdentifier, + EmptyDashboardWithReferences, + TestCorrelation, +} from "../../../tests/Dashboard.test.helpers.js"; import { addLayoutSection } from "../../commands/layout.js"; import { type IChangeRichTextWidgetContent, changeRichTextWidgetContent } from "../../commands/richText.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardRichTextWidgetContentChanged } from "../../events/richText.js"; -import { - EmptyDashboardIdentifier, - EmptyDashboardWithReferences, - TestCorrelation, -} from "../../fixtures/Dashboard.fixtures.js"; -import { TestRichTextItem } from "../../fixtures/Layout.fixtures.js"; import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; +import { TestRichTextItem } from "../../tests/Layout.test.helpers.js"; import { type PrivateDashboardContext } from "../../types/commonTypes.js"; import { EmptyDashboardLayout } from "../dashboard/common/dashboardInitialize.js"; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeVisualizationSwitcherActiveVisualizationHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeVisualizationSwitcherActiveVisualizationHandler.test.ts index 1077e98bb7d..4c80f5d21a5 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeVisualizationSwitcherActiveVisualizationHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/changeVisualizationSwitcherActiveVisualizationHandler.test.ts @@ -4,12 +4,12 @@ import { beforeEach, describe, expect, it } from "vitest"; +import { SimpleDashboardIdentifier } from "../../../tests/SimpleDashboard.test.helpers.js"; import { changeVisualizationSwitcherActiveVisualization } from "../../commands/visualizationSwitcher.js"; import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import type { IDashboardVisualizationSwitcherWidgetActiveVisualizationChanged } from "../../events/visualizationSwitcher.js"; -import { TestVisualizationSwitcherItem } from "../../fixtures/Layout.fixtures.js"; -import { SimpleDashboardIdentifier } from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectVisualizationSwitcherActiveVisualizationByWidgetRef } from "../../store/ui/uiSelectors.js"; +import { TestVisualizationSwitcherItem } from "../../tests/Layout.test.helpers.js"; describe("change visualization switcher active visualization handler", () => { let Tester: DashboardTester; diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/removeDrillsForInsightWidgetHandler.test.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/removeDrillsForInsightWidgetHandler.test.ts index 55e0bc43c73..e63993a42ae 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/removeDrillsForInsightWidgetHandler.test.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/widgets/removeDrillsForInsightWidgetHandler.test.ts @@ -4,6 +4,15 @@ import { beforeEach, describe, expect, it } from "vitest"; import { localIdRef, uriRef } from "@gooddata/sdk-model"; +import { BeforeTestCorrelation, TestCorrelation } from "../../../tests/Dashboard.test.helpers.js"; +import { + DrillToDashboardFromProductAttributeDefinition, + DrillToDashboardWithThreeSectionsLocalIdentifier, + DrillToToInsightFromWonMeasureDefinition, + SimpleDashboardIdentifier, + SimpleDashboardSimpleSortedTableWidgetDrillTargets, + SimpleSortedTableWidgetRef, +} from "../../../tests/SimpleDashboard.test.helpers.js"; import { addDrillTargets } from "../../commands/drillTargets.js"; import { type IRemoveDrillsForInsightWidget, @@ -13,15 +22,6 @@ import { import { type DashboardTester, preloadedTesterFactory } from "../../DashboardTester.js"; import { type IDashboardCommandFailed } from "../../events/general.js"; import { type IDashboardInsightWidgetDrillsRemoved } from "../../events/insight.js"; -import { BeforeTestCorrelation, TestCorrelation } from "../../fixtures/Dashboard.fixtures.js"; -import { - DrillToDashboardFromProductAttributeDefinition, - DrillToDashboardWithThreeSectionsLocalIdentifier, - DrillToToInsightFromWonMeasureDefinition, - SimpleDashboardIdentifier, - SimpleDashboardSimpleSortedTableWidgetDrillTargets, - SimpleSortedTableWidgetRef, -} from "../../fixtures/SimpleDashboard.fixtures.js"; import { selectAnalyticalWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js"; describe("removeDrillsForInsightWidgetHandler", () => { diff --git a/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightAttributesMeta.test.ts b/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightAttributesMeta.test.ts index 331adf48f3f..7c7575c42d9 100644 --- a/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightAttributesMeta.test.ts +++ b/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightAttributesMeta.test.ts @@ -8,17 +8,20 @@ import { type IDashboard, idRef, insightRef } from "@gooddata/sdk-model"; import { createDefaultFilterContext } from "../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../_staging/dateFilterConfig/defaultConfig.js"; +import { + EmptyDashboardIdentifier, + EmptyDashboardWithReferences, +} from "../../tests/Dashboard.test.helpers.js"; import { EmptyDashboardLayout } from "../commandHandlers/dashboard/common/dashboardInitialize.js"; import { addLayoutSection } from "../commands/layout.js"; import { type DashboardTester, preloadedTesterFactory } from "../DashboardTester.js"; -import { EmptyDashboardIdentifier, EmptyDashboardWithReferences } from "../fixtures/Dashboard.fixtures.js"; +import { type IInsightAttributesMeta, queryInsightAttributesMeta } from "../queries/insights.js"; import { PivotTableWithRowAndColumnAttributes, TreemapWithOneMeasureAndViewByDateAndSegmentByDate, TreemapWithSingleMeasureAndViewByFilteredToOneElement, -} from "../fixtures/Insights.fixtures.js"; -import { TestSectionHeader, createTestInsightItem } from "../fixtures/Layout.fixtures.js"; -import { type IInsightAttributesMeta, queryInsightAttributesMeta } from "../queries/insights.js"; +} from "../tests/Insights.test.helpers.js"; +import { TestSectionHeader, createTestInsightItem } from "../tests/Layout.test.helpers.js"; import { type PrivateDashboardContext } from "../types/commonTypes.js"; describe("query insight attributes meta", () => { diff --git a/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightDateDatasets.test.ts b/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightDateDatasets.test.ts index 587f66e8567..2cccb8e1ada 100644 --- a/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightDateDatasets.test.ts +++ b/libs/sdk-ui-dashboard/src/model/queryServices/queryInsightDateDatasets.test.ts @@ -14,22 +14,25 @@ import { import { createDefaultFilterContext } from "../../_staging/dashboard/defaultFilterContext.js"; import { defaultDateFilterConfig } from "../../_staging/dateFilterConfig/defaultConfig.js"; +import { + EmptyDashboardIdentifier, + EmptyDashboardWithReferences, +} from "../../tests/Dashboard.test.helpers.js"; import { EmptyDashboardLayout } from "../commandHandlers/dashboard/common/dashboardInitialize.js"; import { initializeDashboard } from "../commands/dashboard.js"; import { addLayoutSection } from "../commands/layout.js"; import { DashboardTester, preloadedTesterFactory } from "../DashboardTester.js"; +import { type IInsightDateDatasets, queryDateDatasetsForInsight } from "../queries/insights.js"; import { MockAvailabilityWithDifferentRelevance, MockAvailabilityWithSameRelevance, -} from "../fixtures/CatalogAvailability.fixtures.js"; -import { EmptyDashboardIdentifier, EmptyDashboardWithReferences } from "../fixtures/Dashboard.fixtures.js"; +} from "../tests/CatalogAvailability.test.helpers.js"; import { PivotTableWithDateFilter, PivotTableWithRowAndColumnAttributes, TreemapWithOneMeasureAndViewByDateAndSegmentByDate, -} from "../fixtures/Insights.fixtures.js"; -import { TestSectionHeader, createTestInsightItem } from "../fixtures/Layout.fixtures.js"; -import { type IInsightDateDatasets, queryDateDatasetsForInsight } from "../queries/insights.js"; +} from "../tests/Insights.test.helpers.js"; +import { TestSectionHeader, createTestInsightItem } from "../tests/Layout.test.helpers.js"; import { type PrivateDashboardContext } from "../types/commonTypes.js"; function datasetsDigest( diff --git a/libs/sdk-ui-dashboard/src/model/store/catalog/catalog.fixture.ts b/libs/sdk-ui-dashboard/src/model/store/catalog/catalog.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/store/catalog/catalog.fixture.ts rename to libs/sdk-ui-dashboard/src/model/store/catalog/catalog.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/store/catalog/catalogReducers.test.ts b/libs/sdk-ui-dashboard/src/model/store/catalog/catalogReducers.test.ts index 263fa3b07e4..aace7118761 100644 --- a/libs/sdk-ui-dashboard/src/model/store/catalog/catalogReducers.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/catalog/catalogReducers.test.ts @@ -7,7 +7,7 @@ import { describe, expect, it } from "vitest"; import { type ICatalogAttributeHierarchy, type IParameterMetadataObject, idRef } from "@gooddata/sdk-model"; -import { catalogAttributeHierarchies } from "./catalog.fixture.js"; +import { catalogAttributeHierarchies } from "./catalog.test.helpers.js"; import { catalogReducers } from "./catalogReducers.js"; import { type CatalogState } from "./catalogState.js"; import { catalogActions } from "./index.js"; diff --git a/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.fixture.ts b/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.fixture.ts rename to libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.ts index 4adbdb84c56..faef69ac4a2 100644 --- a/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/catalog/catalogSelectors.test.ts @@ -6,7 +6,6 @@ import { describe, expect, it } from "vitest"; import { type IParameterMetadataObject, idRef } from "@gooddata/sdk-model"; -import { catalogDateDatasets, defaultDateHierarchyTemplates } from "./catalogSelectors.fixture.js"; import { selectAdhocDateHierarchies, selectCatalogMeasureParameters, @@ -15,6 +14,7 @@ import { selectCatalogParametersIsLoaded, selectCatalogParametersStatus, } from "./catalogSelectors.js"; +import { catalogDateDatasets, defaultDateHierarchyTemplates } from "./catalogSelectors.test.helpers.js"; import { type ICatalogMeasureParametersState, type ICatalogParametersState } from "./catalogState.js"; describe("catalogSelectors", () => { diff --git a/libs/sdk-ui-dashboard/src/model/store/meta/metaSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/meta/metaSelectors.test.ts index 92b98843a91..8fd6bad6eb7 100644 --- a/libs/sdk-ui-dashboard/src/model/store/meta/metaSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/meta/metaSelectors.test.ts @@ -13,6 +13,7 @@ import { newPositiveAttributeFilter, } from "@gooddata/sdk-model"; +import { TestCorrelation, TestStash } from "../../../tests/Dashboard.test.helpers.js"; import { renameDashboard, setDashboardMeasureValueFilterConfigMode } from "../../commands/dashboard.js"; import { addAttributeFilter, @@ -44,8 +45,7 @@ import { ComplexDashboardFilters, ComplexDashboardIdentifier, ComplexDashboardWidgets, -} from "../../fixtures/ComplexDashboard.fixtures.js"; -import { TestCorrelation, TestStash } from "../../fixtures/Dashboard.fixtures.js"; +} from "../../tests/ComplexDashboard.test.helpers.js"; import { type ExtendedDashboardItem } from "../../types/layoutTypes.js"; import { selectIsDashboardDirty } from "./metaSelectors.js"; diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.test.ts index 98645bffd22..23b63477a21 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.test.ts @@ -1,5 +1,7 @@ // (C) 2023-2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfig/dateFilterConfigReducers.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfig/dateFilterConfigReducers.test.ts index e3ee31e392f..141d46a9dd2 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfig/dateFilterConfigReducers.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfig/dateFilterConfigReducers.test.ts @@ -1,5 +1,7 @@ // (C) 2023-2026 GoodData Corporation +// @vitest-environment node + import { produce } from "immer"; import { cloneDeep } from "lodash-es"; import { describe, expect, it } from "vitest"; diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.test.ts index 2d343bf07b6..33c77c9bb70 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.test.ts @@ -1,5 +1,7 @@ // (C) 2023-2026 GoodData Corporation +// @vitest-environment node + import { produce } from "immer"; import { cloneDeep } from "lodash-es"; import { describe, expect, it } from "vitest"; diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.test.ts index fc0a930774b..1fa6985a59e 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.test.ts @@ -1,5 +1,7 @@ // (C) 2023-2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/filterContext/filterContextUtils.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/filterContext/filterContextUtils.test.ts index 4e0a677a298..c06cd8bf288 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/filterContext/filterContextUtils.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/filterContext/filterContextUtils.test.ts @@ -1,5 +1,7 @@ // (C) 2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutUtils.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutUtils.test.ts index 1bd76430f34..cc1f079f2bc 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutUtils.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/layout/layoutUtils.test.ts @@ -1,5 +1,7 @@ // (C) 2021-2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { type IDashboardLayoutSize } from "@gooddata/sdk-model"; diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersHelpers.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersHelpers.test.ts index d5c1d4a7eef..0aea5eab975 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersHelpers.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersHelpers.test.ts @@ -1,5 +1,7 @@ // (C) 2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersReducers.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersReducers.test.ts index 1127c76f578..58c0ca121f0 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersReducers.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersReducers.test.ts @@ -1,5 +1,7 @@ // (C) 2026 GoodData Corporation +// @vitest-environment node + import { produce } from "immer"; import { describe, expect, it } from "vitest"; diff --git a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersSelectors.test.ts index e58b68ecd9c..a6d3d3279ef 100644 --- a/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/tabs/parameters/parametersSelectors.test.ts @@ -1,5 +1,7 @@ // (C) 2026 GoodData Corporation +// @vitest-environment node + import { describe, expect, it } from "vitest"; import { diff --git a/libs/sdk-ui-dashboard/src/model/store/ui/uiTimezoneOverride.test.ts b/libs/sdk-ui-dashboard/src/model/store/ui/uiTimezoneOverride.test.ts index 629a21d2587..daa64b38ec2 100644 --- a/libs/sdk-ui-dashboard/src/model/store/ui/uiTimezoneOverride.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/ui/uiTimezoneOverride.test.ts @@ -1,5 +1,7 @@ // (C) 2026 GoodData Corporation +// @vitest-environment node + import { produce } from "immer"; import { describe, expect, it } from "vitest"; diff --git a/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.fixture.ts b/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.fixture.ts rename to libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.ts b/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.ts index 25fab5bcc35..27f1140a768 100644 --- a/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.ts +++ b/libs/sdk-ui-dashboard/src/model/store/widgetDrills/widgetDrillSelectors.test.ts @@ -1,5 +1,7 @@ // (C) 2023-2026 GoodData Corporation +// @vitest-environment node + import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { type ObjRef, objRefToString } from "@gooddata/sdk-model"; @@ -8,14 +10,14 @@ import { type Matcher, suppressConsole } from "@gooddata/util"; import { selectDrillTargetsByWidgetRef } from "../drillTargets/drillTargetsSelectors.js"; import { selectIgnoredDrillDownHierarchiesByWidgetRef } from "../tabs/layout/layoutSelectors.js"; +import { selectGlobalDrillsDownAttributeHierarchyByWidgetRef } from "./widgetDrillSelectors.js"; import { availableDrillTargets, catalogAttributeHierarchies, ignoredHierarchies, widgetRef, widgetRefWithoutAvailableDrillTargets, -} from "./widgetDrillSelectors.fixture.js"; -import { selectGlobalDrillsDownAttributeHierarchyByWidgetRef } from "./widgetDrillSelectors.js"; +} from "./widgetDrillSelectors.test.helpers.js"; // `isolate: false` shares one module graph per worker, so the modules mocked below may already have // been evaluated — against their real dependencies — by a test file that ran earlier in the same diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/CatalogAvailability.fixtures.ts b/libs/sdk-ui-dashboard/src/model/tests/CatalogAvailability.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/fixtures/CatalogAvailability.fixtures.ts rename to libs/sdk-ui-dashboard/src/model/tests/CatalogAvailability.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/ComplexDashboard.fixtures.ts b/libs/sdk-ui-dashboard/src/model/tests/ComplexDashboard.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/fixtures/ComplexDashboard.fixtures.ts rename to libs/sdk-ui-dashboard/src/model/tests/ComplexDashboard.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/Insights.fixtures.ts b/libs/sdk-ui-dashboard/src/model/tests/Insights.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/fixtures/Insights.fixtures.ts rename to libs/sdk-ui-dashboard/src/model/tests/Insights.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/Layout.fixtures.ts b/libs/sdk-ui-dashboard/src/model/tests/Layout.test.helpers.ts similarity index 99% rename from libs/sdk-ui-dashboard/src/model/fixtures/Layout.fixtures.ts rename to libs/sdk-ui-dashboard/src/model/tests/Layout.test.helpers.ts index c3cb1d8f1f0..d52e72e37dd 100644 --- a/libs/sdk-ui-dashboard/src/model/fixtures/Layout.fixtures.ts +++ b/libs/sdk-ui-dashboard/src/model/tests/Layout.test.helpers.ts @@ -24,7 +24,7 @@ import { newKpiPlaceholderWidget, } from "../../widgets/placeholders/types.js"; -import { PivotTableWithRowAndColumnAttributes } from "./Insights.fixtures.js"; +import { PivotTableWithRowAndColumnAttributes } from "./Insights.test.helpers.js"; export const TestSectionHeader: IDashboardLayoutSectionHeader = { title: "Test Section", diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/fixtures/TestingDashboardCustomizationLogger.ts b/libs/sdk-ui-dashboard/src/plugins/customizationApis/TestingDashboardCustomizationLogger.test.helpers.ts similarity index 90% rename from libs/sdk-ui-dashboard/src/plugins/customizationApis/fixtures/TestingDashboardCustomizationLogger.ts rename to libs/sdk-ui-dashboard/src/plugins/customizationApis/TestingDashboardCustomizationLogger.test.helpers.ts index fc07965cea2..574b1aa566f 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/fixtures/TestingDashboardCustomizationLogger.ts +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/TestingDashboardCustomizationLogger.test.helpers.ts @@ -1,7 +1,8 @@ // (C) 2022-2026 GoodData Corporation -import { type IDashboardPluginContract_V1 } from "../../plugin.js"; -import { type IDashboardCustomizationLogger } from "../customizationLogging.js"; +import { type IDashboardPluginContract_V1 } from "../plugin.js"; + +import { type IDashboardCustomizationLogger } from "./customizationLogging.js"; export class TestingDashboardCustomizationLogger implements IDashboardCustomizationLogger { private readonly setCurrentPluginImpl: IDashboardCustomizationLogger["setCurrentPlugin"] | undefined; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/dashboardEventHandling.test.ts b/libs/sdk-ui-dashboard/src/plugins/customizationApis/dashboardEventHandling.test.ts index 49acb7d1a35..664dadb0fa1 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/dashboardEventHandling.test.ts +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/dashboardEventHandling.test.ts @@ -1,5 +1,7 @@ // (C) 2021-2026 GoodData Corporation +// @vitest-environment node + import { beforeEach, describe, expect, it, vi } from "vitest"; import { suppressConsole } from "@gooddata/util"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/filterBarCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/filterBarCustomizer.test.tsx index d3adf1af4d3..13bd681c675 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/filterBarCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/filterBarCustomizer.test.tsx @@ -8,7 +8,7 @@ import { HiddenFilterBar } from "../../presentation/filterBar/filterBar/HiddenFi import { type IFilterBarProps } from "../../presentation/filterBar/filterBar/types.js"; import { DefaultFilterBarCustomizer } from "./filterBarCustomizer.js"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/layoutCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/layoutCustomizer.test.tsx index 9f2eb784ca0..739296df772 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/layoutCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/layoutCustomizer.test.tsx @@ -10,8 +10,8 @@ import { type ExtendedDashboardWidget } from "../../model/types/layoutTypes.js"; import { type IDashboardLayoutProps } from "../../presentation/widget/dashboardLayout/types.js"; import { DashboardCustomizationLogger } from "./customizationLogging.js"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; import { DefaultLayoutCustomizer } from "./layoutCustomizer.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/loadingCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/loadingCustomizer.test.tsx index 51b62b51ff2..0182bff66b9 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/loadingCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/loadingCustomizer.test.tsx @@ -5,8 +5,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { type ILoadingProps } from "@gooddata/sdk-ui"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; import { DefaultLoadingCustomizer } from "./loadingCustomizer.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/richTextCustommizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/richTextCustommizer.test.tsx index 19d8d4731c4..d15a5d0746e 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/richTextCustommizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/richTextCustommizer.test.tsx @@ -6,8 +6,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IRichTextWidget, idRef } from "@gooddata/sdk-model"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; import { DefaultRichTextCustomizer } from "./richTextCustomizer.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/titleCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/titleCustomizer.test.tsx index cb6109f69ba..1aa4db5f7e0 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/titleCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/titleCustomizer.test.tsx @@ -5,7 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { type ITitleProps } from "../../presentation/topBar/title/types.js"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { DefaultTitleCustomizer } from "./titleCustomizer.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/topBarCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/topBarCustomizer.test.tsx index 7c1650f4cb4..816d82e4ff5 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/topBarCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/topBarCustomizer.test.tsx @@ -6,7 +6,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IButtonBarProps } from "../../presentation/topBar/buttonBar/types.js"; import { type ITopBarProps } from "../../presentation/topBar/topBar/types.js"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { DefaultTopBarCustomizer } from "./topBarCustomizer.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; diff --git a/libs/sdk-ui-dashboard/src/plugins/customizationApis/vidualisationSwitcherCustomizer.test.tsx b/libs/sdk-ui-dashboard/src/plugins/customizationApis/vidualisationSwitcherCustomizer.test.tsx index 429d71a553e..dac24bf0833 100644 --- a/libs/sdk-ui-dashboard/src/plugins/customizationApis/vidualisationSwitcherCustomizer.test.tsx +++ b/libs/sdk-ui-dashboard/src/plugins/customizationApis/vidualisationSwitcherCustomizer.test.tsx @@ -6,7 +6,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { type IVisualizationSwitcherWidget, idRef } from "@gooddata/sdk-model"; -import { TestingDashboardCustomizationLogger } from "./fixtures/TestingDashboardCustomizationLogger.js"; +import { TestingDashboardCustomizationLogger } from "./TestingDashboardCustomizationLogger.test.helpers.js"; import { type CustomizerMutationsContext, createCustomizerMutationsContext } from "./types.js"; import { EMPTY_MUTATIONS } from "./utils.js"; import { DefaultVisualizationSwitcherCustomizer } from "./visualizationSwitcherCustomizer.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.bodyContent.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.bodyContent.test.tsx new file mode 100644 index 00000000000..329416e8b68 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.bodyContent.test.tsx @@ -0,0 +1,142 @@ +// (C) 2026 GoodData Corporation + +import { render, within } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { dummyBackend } from "@gooddata/sdk-backend-mockingbird"; +import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui"; + +import { IntlWrapper } from "../../../localization/IntlWrapper.js"; +import { AlertingDialogContextProvider } from "../../contexts/AlertingDialogContext.js"; +import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; +import { AlertingDialogStateProvider } from "../state/AlertingDialogStateProvider.js"; +import { + ALERTING_DIALOG_CONTEXT, + AUTOMATIONS_CONTEXT, + SENTINEL_MEASURE, +} from "../tests/alerting.test.helpers.js"; +import { type AlertAttribute, type IDefaultAlertingDialogProps } from "../types.js"; + +import { DefaultAlertingDialog } from "./DefaultAlertingDialog.js"; + +// `isolate: false` shares one module graph per worker, so the real modules imported above may +// already have been replaced by a sibling test file's `vi.mock()` earlier in the same worker. +// Dropping the module registry from `vi.hoisted()` (it runs before this file's own imports, unlike +// any `beforeEach`) makes those imports resolve through the real implementations again. +vi.hoisted(() => { + vi.resetModules(); +}); + +// The two hooks unrelated to slot threading, mocked the same way the state acceptance test mocks them: +// useAlertSupportedMetrics resolves measures from an execution result, useValidateExistingAutomationFilters +// computes staleness against the dashboard's current filters — neither is read by the assertions below. +const { mockUseAlertSupportedMetrics, mockUseValidateExistingAutomationFilters } = vi.hoisted(() => ({ + mockUseAlertSupportedMetrics: vi.fn(), + mockUseValidateExistingAutomationFilters: vi.fn(), +})); + +vi.mock("../state/useAlertSupportedMetrics.js", () => ({ + useAlertSupportedMetrics: mockUseAlertSupportedMetrics, +})); + +vi.mock("../../shared/automationFilters/hooks/useValidateExistingAutomationFilters.js", () => ({ + useValidateExistingAutomationFilters: mockUseValidateExistingAutomationFilters, +})); + +// The filter bar's attribute dropdown reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/addAttributeFilter/AttributesDropdown.js", () => ({ + AttributesDropdown: () => null, +})); + +// A selected attribute filter chip reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/DefaultDashboardAttributeFilter.js", () => ({ + DefaultDashboardAttributeFilter: () => null, +})); + +// Form controls unrelated to the region under test, stubbed for mount cost only. +vi.mock("./components/AlertMeasureSelect.js", () => ({ + AlertMeasureSelect: () => null, +})); +vi.mock("./components/AlertComparisonOperatorSelect.js", () => ({ + AlertComparisonOperatorSelect: () => null, +})); +vi.mock("./components/AlertTriggerModeSelect.js", () => ({ + AlertTriggerModeSelect: () => null, +})); + +// Hoisted so the stale-filters test below can spread-override just the fields it cares about. +const VALID_FILTERS_RESULT = { + isValid: true, + hiddenFilterIsMissingInSavedFilters: false, + hiddenFilterHasDifferentValueInSavedFilter: false, + lockedFilterIsMissingInSavedFilters: false, + lockedFilterHasDifferentValueInSavedFilter: false, + ignoredFilterIsAppliedInSavedFilters: false, + removedFilterIsAppliedInSavedFilters: false, + commonDateFilterIsMissingInSavedVisibleFilters: false, + visibleFilterIsMissingInSavedFilters: false, + visibleFiltersAreMissing: false, + incompatibleSelectionTypeIsAppliedInSavedFilters: false, + filtersAreStale: false, +}; + +beforeEach(() => { + vi.clearAllMocks(); + + mockUseAlertSupportedMetrics.mockReturnValue({ + measureFormatMap: {}, + supportedMeasures: [SENTINEL_MEASURE], + supportedAttributes: [] as AlertAttribute[], + isResultLoading: false, + getAttributeValues: vi.fn(), + getMetricValue: vi.fn(), + }); + + mockUseValidateExistingAutomationFilters.mockReturnValue(VALID_FILTERS_RESULT); +}); + +function renderDialog(props?: Partial, dialogContext = ALERTING_DIALOG_CONTEXT) { + return render( + + + + + + + {}} {...props} /> + + + + + + , + ); +} + +describe("DefaultAlertingDialog topContent/bottomContent", () => { + it("renders topContent first and bottomContent last inside the scrollable content area", () => { + const { baseElement } = renderDialog({ + topContent:
, + bottomContent:
, + }); + const wrapper = baseElement.querySelector( + ".gd-notifications-channel-dialog-content-wrapper", + ) as HTMLElement; + expect(within(wrapper).getByTestId("top-content")).toBeInTheDocument(); + expect(within(wrapper).getByTestId("bottom-content")).toBeInTheDocument(); + expect((wrapper.firstElementChild as HTMLElement).dataset["testid"]).toBe("top-content"); + expect((wrapper.lastElementChild as HTMLElement).dataset["testid"]).toBe("bottom-content"); + }); + + it("renders neither while the dialog context reports loading", () => { + const { queryByTestId } = renderDialog( + { + topContent:
, + bottomContent:
, + }, + { ...ALERTING_DIALOG_CONTEXT, isLoading: true }, + ); + expect(queryByTestId("top-content")).not.toBeInTheDocument(); + expect(queryByTestId("bottom-content")).not.toBeInTheDocument(); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.slots.actionBar.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.slots.actionBar.test.tsx new file mode 100644 index 00000000000..79a04c3aa53 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingDialog/DefaultAlertingDialog.slots.actionBar.test.tsx @@ -0,0 +1,210 @@ +// (C) 2026 GoodData Corporation + +import { fireEvent, render, within } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { dummyBackend } from "@gooddata/sdk-backend-mockingbird"; +import { type IAutomationMetadataObject, idRef } from "@gooddata/sdk-model"; +import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui"; +import { type ISlotProps } from "@gooddata/sdk-ui-kit"; + +import { IntlWrapper } from "../../../localization/IntlWrapper.js"; +import { AlertingDialogContextProvider } from "../../contexts/AlertingDialogContext.js"; +import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; +import { type IAutomationDialogActionBarProps } from "../../shared/slots/types.js"; +import { AlertingDialogStateProvider } from "../state/AlertingDialogStateProvider.js"; +import { + ALERTING_DIALOG_CONTEXT, + AUTOMATIONS_CONTEXT, + SENTINEL_MEASURE, +} from "../tests/alerting.test.helpers.js"; +import { type AlertAttribute, type IDefaultAlertingDialogProps } from "../types.js"; + +import { DefaultAlertingDialog } from "./DefaultAlertingDialog.js"; + +// `isolate: false` shares one module graph per worker, so the real modules imported above may +// already have been replaced by a sibling test file's `vi.mock()` earlier in the same worker. +// Dropping the module registry from `vi.hoisted()` (it runs before this file's own imports, unlike +// any `beforeEach`) makes those imports resolve through the real implementations again. +vi.hoisted(() => { + vi.resetModules(); +}); + +// The two hooks unrelated to slot threading, mocked the same way the state acceptance test mocks them: +// useAlertSupportedMetrics resolves measures from an execution result, useValidateExistingAutomationFilters +// computes staleness against the dashboard's current filters — neither is read by the assertions below. +const { mockUseAlertSupportedMetrics, mockUseValidateExistingAutomationFilters } = vi.hoisted(() => ({ + mockUseAlertSupportedMetrics: vi.fn(), + mockUseValidateExistingAutomationFilters: vi.fn(), +})); + +vi.mock("../state/useAlertSupportedMetrics.js", () => ({ + useAlertSupportedMetrics: mockUseAlertSupportedMetrics, +})); + +vi.mock("../../shared/automationFilters/hooks/useValidateExistingAutomationFilters.js", () => ({ + useValidateExistingAutomationFilters: mockUseValidateExistingAutomationFilters, +})); + +// The filter bar's attribute dropdown reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/addAttributeFilter/AttributesDropdown.js", () => ({ + AttributesDropdown: () => null, +})); + +// A selected attribute filter chip reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/DefaultDashboardAttributeFilter.js", () => ({ + DefaultDashboardAttributeFilter: () => null, +})); + +// Form controls unrelated to the region under test, stubbed for mount cost only. +vi.mock("./components/AlertMeasureSelect.js", () => ({ + AlertMeasureSelect: () => null, +})); +vi.mock("./components/AlertComparisonOperatorSelect.js", () => ({ + AlertComparisonOperatorSelect: () => null, +})); +vi.mock("./components/AlertTriggerModeSelect.js", () => ({ + AlertTriggerModeSelect: () => null, +})); + +// Hoisted so the stale-filters test below can spread-override just the fields it cares about. +const VALID_FILTERS_RESULT = { + isValid: true, + hiddenFilterIsMissingInSavedFilters: false, + hiddenFilterHasDifferentValueInSavedFilter: false, + lockedFilterIsMissingInSavedFilters: false, + lockedFilterHasDifferentValueInSavedFilter: false, + ignoredFilterIsAppliedInSavedFilters: false, + removedFilterIsAppliedInSavedFilters: false, + commonDateFilterIsMissingInSavedVisibleFilters: false, + visibleFilterIsMissingInSavedFilters: false, + visibleFiltersAreMissing: false, + incompatibleSelectionTypeIsAppliedInSavedFilters: false, + filtersAreStale: false, +}; + +beforeEach(() => { + vi.clearAllMocks(); + + mockUseAlertSupportedMetrics.mockReturnValue({ + measureFormatMap: {}, + supportedMeasures: [SENTINEL_MEASURE], + supportedAttributes: [] as AlertAttribute[], + isResultLoading: false, + getAttributeValues: vi.fn(), + getMetricValue: vi.fn(), + }); + + mockUseValidateExistingAutomationFilters.mockReturnValue(VALID_FILTERS_RESULT); +}); + +function renderDialog(props?: Partial, dialogContext = ALERTING_DIALOG_CONTEXT) { + return render( + + + + + + + {}} {...props} /> + + + + + + , + ); +} + +// Edit-mode variant: the Delete button and the "save" label exist only with alertToEdit set. +const ALERT_TO_EDIT: IAutomationMetadataObject = { + type: "automation", + id: "alert-1", + uri: "/alert-1", + ref: idRef("alert-1"), + title: "Alert", + description: "", + production: true, + deprecated: false, + unlisted: false, +}; +const EDIT_MODE_CONTEXT = { ...ALERTING_DIALOG_CONTEXT, alertToEdit: ALERT_TO_EDIT }; + +function CustomActionBar() { + return
; +} + +function WrappingActionBar({ Default, defaultProps }: ISlotProps) { + return ( + <> +
- ); -} - function FormFieldGroup({ label, children }: { label: ReactNode; children: ReactNode }) { return (
diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/AlertDropdown.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/AlertDropdown.tsx deleted file mode 100644 index 864462fa9d4..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/AlertDropdown.tsx +++ /dev/null @@ -1,104 +0,0 @@ -// (C) 2020-2026 GoodData Corporation - -import { Fragment } from "react"; - -import cx from "classnames"; -import { FormattedMessage, defineMessages } from "react-intl"; - -import { Overlay, Separator } from "@gooddata/sdk-ui-kit"; - -import { type IAlertDropdownProps } from "../../types.js"; - -interface IDropdownItemProps { - onClick: () => void; - labelIntlKey: string; - classNames: string; - separator?: "up" | "down"; -} - -function DropdownItem({ onClick, labelIntlKey, classNames }: IDropdownItemProps) { - const cssClasses = cx("gd-list-item gd-menu-item", classNames); - return ( -
- -
- ); -} - -const labelMessages = defineMessages({ - delete: { id: "alerting.alert.menu.delete" }, - pause: { id: "alerting.alert.menu.pause" }, - resume: { id: "alerting.alert.menu.resume" }, - edit: { id: "alerting.alert.menu.edit" }, -}); - -export function AlertDropdown({ - isReadOnly, - paused, - alignTo, - onClose, - onEdit, - onPause, - onDelete, - onResume, -}: IAlertDropdownProps) { - const editItem = { - labelIntlKey: labelMessages.edit.id, - classNames: "s-edit-alert-button", - onClick: onEdit, - }; - const pauseItem = paused - ? { - labelIntlKey: labelMessages.resume.id, - classNames: "s-resume-alert-button", - onClick: onResume, - } - : { - labelIntlKey: labelMessages.pause.id, - classNames: "s-pause-alert-button", - onClick: onPause, - }; - - const deleteItem = { - labelIntlKey: labelMessages.delete.id, - classNames: "s-delete-alert-button deleteItem", - onClick: onDelete, - separator: isReadOnly ? undefined : "up", - }; - - const dropdownActions: IDropdownItemProps[] = isReadOnly - ? [deleteItem] - : [editItem, pauseItem, deleteItem]; - - return ( - -
- {dropdownActions.map((item) => { - return ( - - {item.separator === "up" && } - - {item.separator === "down" && } - - ); - })} -
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.test.tsx deleted file mode 100644 index 4b8a28998a2..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.test.tsx +++ /dev/null @@ -1,62 +0,0 @@ -// (C) 2026 GoodData Corporation - -import { render, waitFor } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; - -import type { IAutomationMetadataObject } from "@gooddata/sdk-model"; - -const fixtures = vi.hoisted(() => { - return { - pauseAlert: vi.fn(), - resumeAlert: vi.fn(), - }; -}); - -vi.mock("../../../contexts/AlertingManagementDialogContext.js", () => ({ - useAlertingManagementDialogContext: () => ({ - pauseAlert: fixtures.pauseAlert, - resumeAlert: fixtures.resumeAlert, - }), -})); - -import { PauseAlertRunner } from "./PauseAlertRunner.js"; - -describe("PauseAlertRunner", () => { - it("passes the updated paused alert returned by the context to onSuccess", async () => { - const originalAlert = { id: "alert-1", alert: { trigger: { state: "ACTIVE" } } }; - const updatedAlert = { id: "alert-1", alert: { trigger: { state: "PAUSED" } } }; - fixtures.pauseAlert.mockResolvedValueOnce(updatedAlert); - const onSuccess = vi.fn(); - - render( - , - ); - - await waitFor(() => { - expect(onSuccess).toHaveBeenCalledWith(updatedAlert, true); - }); - }); - - it("passes the updated resumed alert returned by the context to onSuccess", async () => { - const originalAlert = { id: "alert-1", alert: { trigger: { state: "PAUSED" } } }; - const updatedAlert = { id: "alert-1", alert: { trigger: { state: "ACTIVE" } } }; - fixtures.resumeAlert.mockResolvedValueOnce(updatedAlert); - const onSuccess = vi.fn(); - - render( - , - ); - - await waitFor(() => { - expect(onSuccess).toHaveBeenCalledWith(updatedAlert, false); - }); - }); -}); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.tsx deleted file mode 100644 index 2e3dc571470..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/DefaultAlertingManagementDialog/components/PauseAlertRunner.tsx +++ /dev/null @@ -1,51 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { useEffect } from "react"; - -import { - type IAutomationMetadataObject, - type IAutomationMetadataObjectDefinition, -} from "@gooddata/sdk-model"; -import { type GoodDataSdkError, convertError } from "@gooddata/sdk-ui"; - -import { useAlertingManagementDialogContext } from "../../../contexts/AlertingManagementDialogContext.js"; - -interface IPauseAlertRunnerProps { - alert: IAutomationMetadataObject | null; - pause: boolean; - onSuccess?: ( - alert: IAutomationMetadataObject | IAutomationMetadataObjectDefinition, - pause: boolean, - ) => void; - onError?: (error: GoodDataSdkError, pause: boolean) => void; -} - -export function PauseAlertRunner({ alert, pause, onSuccess, onError }: IPauseAlertRunnerProps) { - const { pauseAlert, resumeAlert } = useAlertingManagementDialogContext(); - - useEffect(() => { - if (!alert) { - return; - } - - if (pause) { - const alertToPause = { - ...alert, - alert: { ...alert.alert, trigger: { ...alert.alert?.trigger, state: "PAUSED" } }, - } as IAutomationMetadataObject; - pauseAlert(alertToPause) - .then((updatedAlert) => onSuccess?.(updatedAlert, true)) - .catch((err) => onError?.(convertError(err), true)); - } else { - const alertToResume = { - ...alert, - alert: { ...alert.alert, trigger: { ...alert.alert?.trigger, state: "ACTIVE" } }, - } as IAutomationMetadataObject; - resumeAlert(alertToResume) - .then((updatedAlert) => onSuccess?.(updatedAlert, false)) - .catch((err) => onError?.(convertError(err), false)); - } - }, [alert, onError, onSuccess, pause, pauseAlert, resumeAlert]); - - return null; -} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/AlertingDialogContextDecorator.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/AlertingDialogContextDecorator.test.tsx index 159933de97d..a64dfa1a1d5 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/AlertingDialogContextDecorator.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/AlertingDialogContextDecorator.test.tsx @@ -77,9 +77,13 @@ import { useAlertingDialogContext, } from "../../contexts/AlertingDialogContext.js"; import { AlertingDialog } from "../AlertingDialog.js"; +import { + ALERTING_DIALOG_CONTEXT, + SENTINEL_CHANNEL, + SENTINEL_MEASURE, +} from "../tests/alerting.test.helpers.js"; import { useAlertDraft } from "./AlertDraftContext.js"; -import { ALERTING_DIALOG_CONTEXT, SENTINEL_CHANNEL, SENTINEL_MEASURE } from "./fixtures.js"; // --------------------------------------------------------------------------- // Fixtures diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/alertStateAcceptance.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/alertStateAcceptance.test.tsx index 3a161ddeb0d..57fac1afed7 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/alertStateAcceptance.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/alertStateAcceptance.test.tsx @@ -9,18 +9,18 @@ import { IntlWrapper } from "../../../localization/IntlWrapper.js"; import { AlertingDialogContextProvider } from "../../contexts/AlertingDialogContext.js"; import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; import { setAlertExecutionParameters } from "../../shared/automationFilters/automationParameters.js"; -import { type AlertAttribute } from "../types.js"; - -import { useAlertActions } from "./AlertActionsContext.js"; -import { useAlertFilters } from "./AlertFiltersContext.js"; -import { AlertingDialogStateProvider } from "./AlertingDialogStateProvider.js"; import { ALERTING_DIALOG_CONTEXT, AUTOMATIONS_CONTEXT, NEXT_FILTER, PARAMETER_REF, SENTINEL_MEASURE, -} from "./fixtures.js"; +} from "../tests/alerting.test.helpers.js"; +import { type AlertAttribute } from "../types.js"; + +import { useAlertActions } from "./AlertActionsContext.js"; +import { useAlertFilters } from "./AlertFiltersContext.js"; +import { AlertingDialogStateProvider } from "./AlertingDialogStateProvider.js"; // --------------------------------------------------------------------------- // Mocks — vi.mock calls are hoisted; factories must not reference top-level diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/fixtures.ts b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/tests/alerting.test.helpers.ts similarity index 97% rename from libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/fixtures.ts rename to libs/sdk-ui-dashboard/src/presentation/automations/alerting/tests/alerting.test.helpers.ts index c78b8d85557..ec538b26664 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/state/fixtures.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/tests/alerting.test.helpers.ts @@ -10,7 +10,7 @@ import { SENTINEL_CHANNEL as SHARED_SENTINEL_CHANNEL, SENTINEL_WIDGET as SHARED_SENTINEL_WIDGET, WORKSPACE_PARAMETER as SHARED_WORKSPACE_PARAMETER, -} from "../../shared/test/fixtures.js"; +} from "../../tests/shared.test.helpers.js"; import { type AlertMetric } from "../types.js"; export const AUTOMATIONS_CONTEXT = SHARED_AUTOMATIONS_CONTEXT; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts index 8f37bbba47f..e8bcc70279c 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/alerting/types.ts @@ -14,13 +14,14 @@ import { type IWidget, } from "@gooddata/sdk-model"; import { type GoodDataSdkError } from "@gooddata/sdk-ui"; +import { type ISlotProps } from "@gooddata/sdk-ui-kit"; import { + type IAutomationDialogActionBarProps, type IAutomationDialogDestinationProps, type IAutomationDialogFiltersProps, type IAutomationDialogHeaderProps, type IAutomationDialogRecipientsProps, - type ISlotProps, } from "../shared/slots/types.js"; /// @@ -163,13 +164,13 @@ export interface IAlertingDialogFiltersProps extends IAutomationDialogFiltersPro export interface IAlertingDialogSlots { /** * Wraps or replaces the dialog header (the title input row). Must have a stable reference - * identity — see {@link ISlotProps}. + * identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. */ Header?: ComponentType>; /** * Wraps or replaces the dialog's filters region (the filter and parameter chips). Must have - * a stable reference identity — see {@link ISlotProps}. + * a stable reference identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog: not while the dialog context reports loading, * and not while the stale-filters confirmation step is shown. @@ -182,7 +183,7 @@ export interface IAlertingDialogSlots { /** * Wraps or replaces the dialog's destination region (the "Action" row selecting the - * notification channel). Must have a stable reference identity — see {@link ISlotProps}. + * notification channel). Must have a stable reference identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog — not while the dialog context reports loading, * not while the stale-filters confirmation step is shown — **and only when more than one @@ -193,12 +194,29 @@ export interface IAlertingDialogSlots { /** * Wraps or replaces the dialog's recipients region. Must have a stable reference identity — - * see {@link ISlotProps}. + * see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog: not while the dialog context reports loading, * and not while the stale-filters confirmation step is shown. */ Recipients?: ComponentType>; + + /** + * Wraps or replaces the dialog's action bar (the footer row: documentation link, Delete in + * edit mode, Cancel and the submit button). Must have a stable reference identity — see + * {@link @gooddata/sdk-ui-kit#ISlotProps}. + * + * Renders only in the fully rendered dialog: not while the dialog context reports loading + * (the loading dialog keeps its own footer), and not while the stale-filters confirmation + * step is shown. + * + * A replacement that does not render `Default` loses the submit button's Enter-key detection + * id (Enter no longer submits), the validation aria wiring, and the default row's ordering. + * Wraps that render `` keep everything; note the Enter-key path + * invokes the dialog's own submit handler and disabled state, so `defaultProps` overrides + * affect the buttons only. + */ + ActionBar?: ComponentType>; } /** @@ -220,7 +238,7 @@ export interface IDefaultAlertingDialogProps extends IAlertingDialogProps { * * @example * The dialog is reached through the `Dashboard` component override; define slot components at - * module scope (see {@link ISlotProps}): + * module scope (see {@link @gooddata/sdk-ui-kit#ISlotProps}): * ```tsx * function HeaderWithBanner({ Default, defaultProps }: ISlotProps) { * return ( @@ -239,6 +257,19 @@ export interface IDefaultAlertingDialogProps extends IAlertingDialogProps { * ``` */ slots?: IAlertingDialogSlots; + + /** + * Content rendered as the first child of the dialog's scrollable content area, above the + * form. Rendered only in the fully rendered dialog: not while the dialog context reports + * loading, and not while the stale-filters confirmation step is shown. + */ + topContent?: ReactNode; + + /** + * Content rendered as the last child of the dialog's scrollable content area, below the + * form. Same rendering conditions as {@link IDefaultAlertingDialogProps.topContent}. + */ + bottomContent?: ReactNode; } /** diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.bodyContent.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.bodyContent.test.tsx new file mode 100644 index 00000000000..1a593b86046 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.bodyContent.test.tsx @@ -0,0 +1,141 @@ +// (C) 2026 GoodData Corporation + +import { fireEvent, render, within } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { dummyBackend } from "@gooddata/sdk-backend-mockingbird"; +import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui"; + +import { IntlWrapper } from "../../../localization/IntlWrapper.js"; +import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; +import { ScheduledEmailDialogContextProvider } from "../../contexts/ScheduledEmailDialogContext.js"; +import { ScheduledEmailDialogStateProvider } from "../state/ScheduledEmailDialogStateProvider.js"; +import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "../tests/scheduledEmail.test.helpers.js"; +import { type IDefaultScheduledEmailDialogProps } from "../types.js"; + +import { DefaultScheduledEmailDialog } from "./DefaultScheduledEmailDialog.js"; + +// `isolate: false` shares one module graph per worker, so the real modules imported above may +// already have been replaced by a sibling test file's `vi.mock()` earlier in the same worker. +// Dropping the module registry from `vi.hoisted()` (it runs before this file's own imports, unlike +// any `beforeEach`) makes those imports resolve through the real implementations again. +vi.hoisted(() => { + vi.resetModules(); +}); + +// The one hook unrelated to slot threading, mocked the same way the SE state acceptance test mocks it: +// useValidateExistingAutomationFilters computes staleness against the dashboard's current filters and is +// not read by the assertions below. +const { mockUseValidateExistingAutomationFilters } = vi.hoisted(() => ({ + mockUseValidateExistingAutomationFilters: vi.fn(), +})); + +vi.mock("../../shared/automationFilters/hooks/useValidateExistingAutomationFilters.js", () => ({ + useValidateExistingAutomationFilters: mockUseValidateExistingAutomationFilters, +})); + +// The filter bar's attribute dropdown reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/addAttributeFilter/AttributesDropdown.js", () => ({ + AttributesDropdown: () => null, +})); + +// A selected attribute filter chip reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/DefaultDashboardAttributeFilter.js", () => ({ + DefaultDashboardAttributeFilter: () => null, +})); + +// RecipientsSelect renders for real under this harness; it reaches the backend through +// useBackendStrict/useWorkspaceStrict, so the harness provides a real (dummy) backend and +// workspace — the search never activates in these tests, so the backend is never queried. + +const VALID_FILTERS_RESULT = { + isValid: true, + hiddenFilterIsMissingInSavedFilters: false, + hiddenFilterHasDifferentValueInSavedFilter: false, + lockedFilterIsMissingInSavedFilters: false, + lockedFilterHasDifferentValueInSavedFilter: false, + ignoredFilterIsAppliedInSavedFilters: false, + removedFilterIsAppliedInSavedFilters: false, + commonDateFilterIsMissingInSavedVisibleFilters: false, + visibleFilterIsMissingInSavedFilters: false, + visibleFiltersAreMissing: false, + incompatibleSelectionTypeIsAppliedInSavedFilters: false, + filtersAreStale: false, +}; + +beforeEach(() => { + vi.clearAllMocks(); + + mockUseValidateExistingAutomationFilters.mockReturnValue(VALID_FILTERS_RESULT); +}); + +function renderDialog( + props?: Partial, + dialogContext = SCHEDULED_EMAIL_DIALOG_CONTEXT, +) { + return render( + + + + + + + {}} {...props} /> + + + + + + , + ); +} + +// The dialog's Overlay aligns itself (and lifts the visibility:hidden it renders with initially) +// on a real timer, not inside React's commit phase - the tab is only accessible-by-role once that +// has run, so finding it needs to poll rather than query synchronously. +async function selectFiltersTab(baseElement: HTMLElement) { + const tab = await within(baseElement).findByRole("tab", { name: /filters/i }); + fireEvent.click(tab); +} + +describe("DefaultScheduledEmailDialog topContent/bottomContent", () => { + it("renders topContent first and bottomContent last inside the scrollable content area", () => { + const { baseElement } = renderDialog({ + topContent:
, + bottomContent:
, + }); + const wrapper = baseElement.querySelector( + ".gd-notifications-channel-dialog-content-wrapper", + ) as HTMLElement; + expect(within(wrapper).getByTestId("top-content")).toBeInTheDocument(); + expect(within(wrapper).getByTestId("bottom-content")).toBeInTheDocument(); + expect((wrapper.firstElementChild as HTMLElement).dataset["testid"]).toBe("top-content"); + expect((wrapper.lastElementChild as HTMLElement).dataset["testid"]).toBe("bottom-content"); + }); + + it("renders neither while the dialog context reports loading", () => { + const { queryByTestId } = renderDialog( + { + topContent:
, + bottomContent:
, + }, + { ...SCHEDULED_EMAIL_DIALOG_CONTEXT, isLoading: true }, + ); + expect(queryByTestId("top-content")).not.toBeInTheDocument(); + expect(queryByTestId("bottom-content")).not.toBeInTheDocument(); + }); + + it("renders both on the General and the Filters tab", async () => { + const { baseElement, getByTestId } = renderDialog({ + topContent:
, + bottomContent:
, + }); + + expect(getByTestId("top-content")).toBeInTheDocument(); + expect(getByTestId("bottom-content")).toBeInTheDocument(); + + await selectFiltersTab(baseElement); + expect(getByTestId("top-content")).toBeInTheDocument(); + expect(getByTestId("bottom-content")).toBeInTheDocument(); + }); +}); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.slots.actionBar.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.slots.actionBar.test.tsx new file mode 100644 index 00000000000..959258fff0f --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.slots.actionBar.test.tsx @@ -0,0 +1,207 @@ +// (C) 2026 GoodData Corporation + +import { fireEvent, render, within } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { dummyBackend } from "@gooddata/sdk-backend-mockingbird"; +import { type IAutomationMetadataObject, idRef } from "@gooddata/sdk-model"; +import { BackendProvider, WorkspaceProvider } from "@gooddata/sdk-ui"; +import { type ISlotProps } from "@gooddata/sdk-ui-kit"; + +import { IntlWrapper } from "../../../localization/IntlWrapper.js"; +import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; +import { ScheduledEmailDialogContextProvider } from "../../contexts/ScheduledEmailDialogContext.js"; +import { type IAutomationDialogActionBarProps } from "../../shared/slots/types.js"; +import { ScheduledEmailDialogStateProvider } from "../state/ScheduledEmailDialogStateProvider.js"; +import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "../tests/scheduledEmail.test.helpers.js"; +import { type IDefaultScheduledEmailDialogProps } from "../types.js"; + +import { DefaultScheduledEmailDialog } from "./DefaultScheduledEmailDialog.js"; + +// `isolate: false` shares one module graph per worker, so the real modules imported above may +// already have been replaced by a sibling test file's `vi.mock()` earlier in the same worker. +// Dropping the module registry from `vi.hoisted()` (it runs before this file's own imports, unlike +// any `beforeEach`) makes those imports resolve through the real implementations again. +vi.hoisted(() => { + vi.resetModules(); +}); + +// The one hook unrelated to slot threading, mocked the same way the SE state acceptance test mocks it: +// useValidateExistingAutomationFilters computes staleness against the dashboard's current filters and is +// not read by the assertions below. +const { mockUseValidateExistingAutomationFilters } = vi.hoisted(() => ({ + mockUseValidateExistingAutomationFilters: vi.fn(), +})); + +vi.mock("../../shared/automationFilters/hooks/useValidateExistingAutomationFilters.js", () => ({ + useValidateExistingAutomationFilters: mockUseValidateExistingAutomationFilters, +})); + +// The filter bar's attribute dropdown reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/addAttributeFilter/AttributesDropdown.js", () => ({ + AttributesDropdown: () => null, +})); + +// A selected attribute filter chip reads the dashboard redux store, which this harness does not mount. +vi.mock("../../../filterBar/attributeFilter/DefaultDashboardAttributeFilter.js", () => ({ + DefaultDashboardAttributeFilter: () => null, +})); + +// RecipientsSelect renders for real under this harness; it reaches the backend through +// useBackendStrict/useWorkspaceStrict, so the harness provides a real (dummy) backend and +// workspace — the search never activates in these tests, so the backend is never queried. + +const VALID_FILTERS_RESULT = { + isValid: true, + hiddenFilterIsMissingInSavedFilters: false, + hiddenFilterHasDifferentValueInSavedFilter: false, + lockedFilterIsMissingInSavedFilters: false, + lockedFilterHasDifferentValueInSavedFilter: false, + ignoredFilterIsAppliedInSavedFilters: false, + removedFilterIsAppliedInSavedFilters: false, + commonDateFilterIsMissingInSavedVisibleFilters: false, + visibleFilterIsMissingInSavedFilters: false, + visibleFiltersAreMissing: false, + incompatibleSelectionTypeIsAppliedInSavedFilters: false, + filtersAreStale: false, +}; + +beforeEach(() => { + vi.clearAllMocks(); + + mockUseValidateExistingAutomationFilters.mockReturnValue(VALID_FILTERS_RESULT); +}); + +function renderDialog( + props?: Partial, + dialogContext = SCHEDULED_EMAIL_DIALOG_CONTEXT, +) { + return render( + + + + + + + {}} {...props} /> + + + + + + , + ); +} + +// Edit-mode variant: the Delete button and the "Save" label exist only with scheduledExportToEdit set. +const SCHEDULED_EXPORT_TO_EDIT: IAutomationMetadataObject = { + type: "automation", + id: "schedule-1", + uri: "/schedule-1", + ref: idRef("schedule-1"), + title: "Schedule", + description: "", + production: true, + deprecated: false, + unlisted: false, +}; +const EDIT_MODE_CONTEXT = { + ...SCHEDULED_EMAIL_DIALOG_CONTEXT, + scheduledExportToEdit: SCHEDULED_EXPORT_TO_EDIT, +}; + +function CustomActionBar() { + return
; +} + +function WrappingActionBar({ Default, defaultProps }: ISlotProps) { + return ( + <> +
- ); -} - export function ScheduledMailDialogRenderer({ onBack, onCancel, @@ -125,12 +92,15 @@ export function ScheduledMailDialogRenderer({ onSubmit, onSuccess, slots, + topContent, + bottomContent, }: IDefaultScheduledEmailDialogProps) { const HeaderSlot = slots?.Header; const FiltersSlot = slots?.Filters; const TimezoneSlot = slots?.Timezone; const DestinationSlot = slots?.Destination; const RecipientsSlot = slots?.Recipients; + const ActionBarSlot = slots?.ActionBar; const intl = useIntl(); @@ -422,6 +392,33 @@ export function ScheduledMailDialogRenderer({ externalRecipientOverride, }; + const actionBarDefaultProps: IAutomationDialogActionBarProps = { + cancelButtonText: intl.formatMessage({ id: "cancel" }), + submitButtonText: scheduledExportToEdit + ? intl.formatMessage({ id: "dialogs.schedule.email.save" }) + : intl.formatMessage({ id: "dialogs.schedule.email.create" }), + onCancel: () => onCancel?.(), + onSubmit: handleSaveScheduledEmail, + isSubmitDisabled: submitDisabled, + isSaving: isSavingScheduledEmail, + submitButtonTooltipText: isExecutionTimestampMode + ? intl.formatMessage({ id: "dialogs.schedule.email.save.executionTimestampMode" }) + : undefined, + ...(isWhiteLabeled + ? {} + : { + helpLinkText: intl.formatMessage({ id: helpTextId }), + helpLinkHref: + "https://www.gooddata.com/docs/cloud/create-dashboards/automation/scheduled-exports/#ScheduleExportsinDashboards-ScheduleExport", + }), + ...(scheduledExportToEdit + ? { + deleteButtonText: intl.formatMessage({ id: "delete" }), + onDelete: () => setScheduledEmailToDelete(editedAutomation), + } + : {}), + }; + return ( <> ( - setScheduledEmailToDelete(editedAutomation)} - /> - )} + footerLeftRenderer={ + ActionBarSlot + ? undefined + : () => ( + + ) + } + footerRenderer={ + ActionBarSlot + ? () => ( + + ) + : undefined + } isSubmitDisabled={submitDisabled} submitButtonTooltipText={ isExecutionTimestampMode @@ -526,6 +537,7 @@ export function ScheduledMailDialogRenderer({ "gd-notification-channel-dialog-with-tabs": tabs.length > 1, })} > + {topContent}
{selectedTabId === "filters" ? (
)} + {bottomContent} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentSettings.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentSettings.test.tsx index 459d85c413a..7f2dc76162c 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentSettings.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentSettings.test.tsx @@ -65,12 +65,12 @@ describe("AttachmentSettings", () => { expect(orientationLabel).toHaveAttribute("for", orientationDropdown.id); }); - it("should default CSV settings to comma", () => { + it("should default CSV settings to inherit", () => { renderComponent(); openSettings(); - expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Comma"); + expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Inherit"); }); it("should prefill existing custom CSV delimiter", () => { diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentSettings.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentSettings.tsx index ff324235f47..1667ed89b52 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentSettings.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/AttachmentSettings.tsx @@ -5,7 +5,6 @@ import { type Ref, useId, useMemo, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { - DEFAULT_CSV_DELIMITER, type IExportDefinitionVisualizationObjectSettings, getCsvDelimiterState, getCsvDelimiterValidationError, @@ -90,7 +89,6 @@ export function AttachmentSettings({ type, settings, onSettingsChange }: IAttach const legacyOrientation = settings.orientation; const legacyPageOrientation = mapLegacyOrientationToPageOrientation(legacyOrientation); const resolvedDefaultPageSize = settings.pageSize ?? DEFAULT_PDF_PAGE_SIZE; - const resolvedCsvDelimiter = settings.delimiter ?? DEFAULT_CSV_DELIMITER; const resolvedCsvState = getCsvDelimiterState(settings.delimiter); const [mergeHeaders, setMergeHeaders] = useState(settings.mergeHeaders ?? true); const [exportInfo, setExportInfo] = useState(settings.exportInfo ?? true); @@ -181,7 +179,7 @@ export function AttachmentSettings({ type, settings, onSettingsChange }: IAttach csvDelimiterValue.selectedPreset === "custom" ? getCsvDelimiterValidationError(csvDelimiterValue.customDelimiter) : undefined; - const isCsvSettingsDirty = selectedDelimiter !== resolvedCsvDelimiter; + const isCsvSettingsDirty = selectedDelimiter !== settings.delimiter; const isSettingsDirty = isPdfTabular ? isPdfSettingsDirty : isCsv diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.test.ts deleted file mode 100644 index 491b0c207d9..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -// (C) 2026 GoodData Corporation - -import { renderHook } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; - -import { - DashboardAttributeFilterConfigModeValues, - DashboardDateFilterConfigModeValues, - type FilterContextItem, -} from "@gooddata/sdk-model"; - -// --------------------------------------------------------------------------- -// Mocks -// --------------------------------------------------------------------------- - -vi.mock("../../../contexts/ScheduledEmailDialogContext.js", () => ({ - useScheduledEmailDialogContext: () => ({ - commonDateFilterMode: DashboardDateFilterConfigModeValues.ACTIVE, - dateFiltersModeMap: new Map([["date-ds-1", DashboardDateFilterConfigModeValues.HIDDEN]]), - attributeFiltersModeMap: new Map([ - ["attr-1", DashboardAttributeFilterConfigModeValues.HIDDEN], - ["attr-2", DashboardAttributeFilterConfigModeValues.ACTIVE], - ]), - }), -})); - -vi.mock("../../../shared/hooks/useFiltersNamings.js", () => ({ - useFiltersNamings: (filters: FilterContextItem[]) => filters.map((f: any) => ({ id: f.id ?? "no-id" })), -})); - -import { useFiltersForDashboardScheduledExportInfo } from "./useFiltersForDashboardScheduledExportInfo.js"; - -// --------------------------------------------------------------------------- -// Fixtures -// --------------------------------------------------------------------------- - -const commonDateFilter: FilterContextItem = { - dateFilter: { type: "relative", granularity: "GDC.time.year" }, -} as any; - -const hiddenDateFilter: FilterContextItem = { - dateFilter: { - type: "relative", - granularity: "GDC.time.month", - localIdentifier: "date-ds-1", - dataSet: { identifier: "date-ds-1", type: "identifier" }, - }, -} as any; - -const visibleDateFilter: FilterContextItem = { - dateFilter: { - type: "relative", - granularity: "GDC.time.month", - localIdentifier: "date-ds-2", - dataSet: { identifier: "date-ds-2", type: "identifier" }, - }, -} as any; - -const hiddenAttrFilter: FilterContextItem = { - attributeFilter: { - localIdentifier: "attr-1", - attributeElements: { type: "values", values: [] }, - displayForm: { identifier: "df-1", type: "identifier" }, - negativeSelection: false, - }, -} as any; - -const visibleAttrFilter: FilterContextItem = { - attributeFilter: { - localIdentifier: "attr-2", - attributeElements: { type: "values", values: [] }, - displayForm: { identifier: "df-2", type: "identifier" }, - negativeSelection: false, - }, -} as any; - -// --------------------------------------------------------------------------- -// Tests -// --------------------------------------------------------------------------- - -describe("useFiltersForDashboardScheduledExportInfo (context-aware)", () => { - it("filters out hidden common date filter", () => { - // The mock has commonDateFilterMode = ACTIVE, so common date filter should be visible. - // Let's just verify it passes through when visible. - const { result } = renderHook(() => - useFiltersForDashboardScheduledExportInfo({ effectiveFilters: [commonDateFilter] }), - ); - expect(result.current).toHaveLength(1); - }); - - it("filters out hidden date dataset filter", () => { - const { result } = renderHook(() => - useFiltersForDashboardScheduledExportInfo({ - effectiveFilters: [hiddenDateFilter, visibleDateFilter], - }), - ); - // hiddenDateFilter (date-ds-1) should be removed, visibleDateFilter should remain - expect(result.current).toHaveLength(1); - }); - - it("filters out hidden attribute filter", () => { - const { result } = renderHook(() => - useFiltersForDashboardScheduledExportInfo({ - effectiveFilters: [hiddenAttrFilter, visibleAttrFilter], - }), - ); - // attr-1 is HIDDEN, attr-2 is ACTIVE - expect(result.current).toHaveLength(1); - }); - - it("returns empty array when no filters provided", () => { - const { result } = renderHook(() => - useFiltersForDashboardScheduledExportInfo({ effectiveFilters: [] }), - ); - expect(result.current).toHaveLength(0); - }); - - it("returns empty array when effectiveFilters is undefined", () => { - const { result } = renderHook(() => useFiltersForDashboardScheduledExportInfo({})); - expect(result.current).toHaveLength(0); - }); -}); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.ts deleted file mode 100644 index b5343a71dd9..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/hooks/useFiltersForDashboardScheduledExportInfo.ts +++ /dev/null @@ -1,73 +0,0 @@ -// (C) 2024-2026 GoodData Corporation - -import { compact } from "lodash-es"; - -import { - type DashboardAttributeFilterConfigMode, - DashboardAttributeFilterConfigModeValues, - type DashboardDateFilterConfigMode, - DashboardDateFilterConfigModeValues, - type FilterContextItem, - dashboardAttributeFilterItemLocalIdentifier, - isDashboardAttributeFilterItem, - isDashboardCommonDateFilter, - isDashboardDateFilter, -} from "@gooddata/sdk-model"; -import { type DateFilterOption } from "@gooddata/sdk-ui-filters"; - -import { useScheduledEmailDialogContext } from "../../../contexts/ScheduledEmailDialogContext.js"; -import { useFiltersNamings } from "../../../shared/hooks/useFiltersNamings.js"; - -export interface IAttachmentFilterInfo { - id: string; - title: string; - subtitle: string; - attributeFilterValues?: (string | null)[]; - isAttributeFilterNegative?: boolean; - dateFilterOption?: DateFilterOption; -} - -interface IUseFiltersForDashboardScheduledExportInfoProps { - /** - * Effective filters - original stored filters or current effective dashboard filters (without cross-filtering). - */ - effectiveFilters?: FilterContextItem[]; -} - -export const useFiltersForDashboardScheduledExportInfo = ({ - effectiveFilters = [], -}: IUseFiltersForDashboardScheduledExportInfoProps) => { - // Remove hidden dashboard filters, we don't want to display them. - const { commonDateFilterMode, dateFiltersModeMap, attributeFiltersModeMap } = - useScheduledEmailDialogContext(); - const filtersToDisplay = removeHiddenFilters( - effectiveFilters, - commonDateFilterMode, - dateFiltersModeMap, - attributeFiltersModeMap, - ); - - return compact(useFiltersNamings(filtersToDisplay)); -}; - -const removeHiddenFilters = ( - filters: FilterContextItem[], - commonDateFilterMode: DashboardDateFilterConfigMode, - dateFiltersModeMap: Map, - attributeFiltersModeMap: Map, -) => { - return filters.filter((filter) => { - if (isDashboardCommonDateFilter(filter)) { - return commonDateFilterMode !== DashboardDateFilterConfigModeValues.HIDDEN; - } else if (isDashboardDateFilter(filter) && filter.dateFilter.localIdentifier) { - const mode = dateFiltersModeMap.get(filter.dateFilter.localIdentifier); - return mode !== DashboardDateFilterConfigModeValues.HIDDEN; - } else if (isDashboardAttributeFilterItem(filter)) { - const localIdentifier = dashboardAttributeFilterItemLocalIdentifier(filter); - const mode = localIdentifier ? attributeFiltersModeMap.get(localIdentifier) : undefined; - return mode !== DashboardAttributeFilterConfigModeValues.HIDDEN; - } - - return true; - }); -}; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/components/ScheduledEmail.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/components/ScheduledEmail.tsx deleted file mode 100644 index c78f58997b4..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/DefaultScheduledEmailManagementDialog/components/ScheduledEmail.tsx +++ /dev/null @@ -1,144 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { useCallback } from "react"; - -import cx from "classnames"; -import { FormattedMessage, useIntl } from "react-intl"; - -import { - type IAutomationMetadataObject, - type INotificationChannelIdentifier, - type INotificationChannelMetadataObject, -} from "@gooddata/sdk-model"; -import { - Bubble, - BubbleHoverTrigger, - IconInsight, - IconSimplifiedDashboard, - IconWarning, - SELECT_ITEM_ACTION, - ShortenedText, -} from "@gooddata/sdk-ui-kit"; -import { useTheme } from "@gooddata/sdk-ui-theme-provider"; - -import { gdColorNegative, gdColorStateBlank } from "../../../../constants/colors.js"; -import { useAutomationsContext } from "../../../contexts/AutomationsContext.js"; -import { isVisualisationAutomation } from "../../../shared/utils/automationUtils.js"; -import { useScheduleValidation } from "../../DefaultScheduledEmailDialog/hooks/useScheduleValidation.js"; - -type IAction = "scheduleEmail" | "delete" | typeof SELECT_ITEM_ACTION; - -interface IScheduledEmailProps { - onDelete: (scheduledEmail: IAutomationMetadataObject) => void; - onEdit: (scheduledEmail: IAutomationMetadataObject) => void; - scheduledEmail: IAutomationMetadataObject; - notificationChannels: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; - focusedAction?: IAction; -} - -const ICON_TOOLTIP_ALIGN_POINTS = [ - { align: "cr cl", offset: { x: 0, y: 0 } }, - { align: "cl cr", offset: { x: 0, y: 0 } }, -]; - -const TEXT_TOOLTIP_ALIGN_POINTS = [ - { align: "tc bc", offset: { x: 0, y: 0 } }, - { align: "bc tc", offset: { x: 0, y: 0 } }, -]; - -export function ScheduledEmail({ - scheduledEmail, - onDelete, - onEdit, - notificationChannels, - focusedAction, -}: IScheduledEmailProps) { - const theme = useTheme(); - - const { currentUser, features } = useAutomationsContext(); - const canEdit = - features.canManageWorkspace || (currentUser && currentUser.login === scheduledEmail.createdBy?.login); - - const { isValid } = useScheduleValidation(scheduledEmail); - const intl = useIntl(); - const cronDescription = scheduledEmail.schedule?.cronDescription; - const webhookTitle = notificationChannels.find( - (channel) => channel.id === scheduledEmail.notificationChannel, - )?.title; - const dashboardTitle = scheduledEmail.exportDefinitions?.find((def) => def.title)?.title; - const isWidget = isVisualisationAutomation(scheduledEmail); - const iconColor = theme?.palette?.complementary?.c6 ?? gdColorStateBlank; - const iconColorError = theme?.palette?.error?.base ?? gdColorNegative; - const iconComponent = isValid ? ( - isWidget ? ( - - ) : ( - - ) - ) : ( - - ); - - const subtitle = [cronDescription, webhookTitle, dashboardTitle].filter(Boolean).join(" • "); - - const handleClick = useCallback(() => { - onEdit(scheduledEmail); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [scheduledEmail]); - - return ( -
-
-
- {iconComponent} -
-
-
- - - {scheduledEmail.title ?? - intl.formatMessage({ id: "dialogs.schedule.email.title.placeholder" })} - - -
-
- - - {subtitle} - - -
-
-
-
- - onDelete(scheduledEmail)} - /> - - - - -
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogContextDecorator.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogContextDecorator.test.tsx index 8ccec5086c6..2091d4a3675 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogContextDecorator.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogContextDecorator.test.tsx @@ -71,8 +71,12 @@ import { useScheduledEmailDialogContext, } from "../../contexts/ScheduledEmailDialogContext.js"; import { ScheduledEmailDialog } from "../ScheduledEmailDialog.js"; +import { + AUTOMATIONS_CONTEXT, + SCHEDULED_EMAIL_DIALOG_CONTEXT, + SENTINEL_CHANNEL, +} from "../tests/scheduledEmail.test.helpers.js"; -import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT, SENTINEL_CHANNEL } from "./fixtures.js"; import { useScheduledExportDraft } from "./ScheduledExportDraftContext.js"; // --------------------------------------------------------------------------- diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogStateProvider.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogStateProvider.test.tsx index 70132d3be54..780bc31606d 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogStateProvider.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/ScheduledEmailDialogStateProvider.test.tsx @@ -86,8 +86,12 @@ function PassthroughDecoratorComponent({ children }: { children?: ReactNode }) { import { IntlWrapper } from "../../../localization/IntlWrapper.js"; import { useScheduledEmailDialogContext } from "../../contexts/ScheduledEmailDialogContext.js"; import { ScheduledEmailDialog } from "../ScheduledEmailDialog.js"; +import { + AUTOMATIONS_CONTEXT, + CURRENT_USER, + SCHEDULED_EMAIL_DIALOG_CONTEXT, +} from "../tests/scheduledEmail.test.helpers.js"; -import { AUTOMATIONS_CONTEXT, CURRENT_USER, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "./fixtures.js"; import { useScheduledExportActions } from "./ScheduledExportActionsContext.js"; import { useScheduledExportData } from "./ScheduledExportDataContext.js"; import { useScheduledExportDraft } from "./ScheduledExportDraftContext.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx index 77baec7b066..cc49ce5a838 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportDialogState.shape.test.tsx @@ -77,13 +77,13 @@ import { type IScheduledEmailDialogContextValue, ScheduledEmailDialogContextProvider, } from "../../contexts/ScheduledEmailDialogContext.js"; - import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT, SENTINEL_INSIGHT, SENTINEL_WIDGET, -} from "./fixtures.js"; +} from "../tests/scheduledEmail.test.helpers.js"; + import { ScheduledEmailDialogStateProvider } from "./ScheduledEmailDialogStateProvider.js"; import { useScheduledExportActions } from "./ScheduledExportActionsContext.js"; import { useScheduledExportData } from "./ScheduledExportDataContext.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportParametersWire.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportParametersWire.test.tsx index 4707f19292b..243f8800753 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportParametersWire.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportParametersWire.test.tsx @@ -49,15 +49,15 @@ import { type IScheduledEmailDialogContextValue, ScheduledEmailDialogContextProvider, } from "../../contexts/ScheduledEmailDialogContext.js"; -import { dashboardParameter } from "../../shared/automationFilters/parameterFixtures.js"; - +import { dashboardParameter } from "../../tests/parameterFixtures.test.helpers.js"; import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT, SENTINEL_INSIGHT, SENTINEL_WIDGET, WORKSPACE_PARAMETER, -} from "./fixtures.js"; +} from "../tests/scheduledEmail.test.helpers.js"; + import { ScheduledEmailDialogStateProvider } from "./ScheduledEmailDialogStateProvider.js"; import { useScheduledExportActions } from "./ScheduledExportActionsContext.js"; import { useScheduledExportDraft } from "./ScheduledExportDraftContext.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateAcceptance.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateAcceptance.test.tsx index dae59ebf1b8..68d817c3b20 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateAcceptance.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateAcceptance.test.tsx @@ -41,8 +41,12 @@ import { IntlWrapper } from "../../../localization/IntlWrapper.js"; import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; import { ScheduledEmailDialogContextProvider } from "../../contexts/ScheduledEmailDialogContext.js"; import { useAutomationFiltersSelect } from "../../shared/automationFilters/useAutomationFiltersSelect.js"; +import { + AUTOMATIONS_CONTEXT, + NEXT_FILTER, + SCHEDULED_EMAIL_DIALOG_CONTEXT, +} from "../tests/scheduledEmail.test.helpers.js"; -import { AUTOMATIONS_CONTEXT, NEXT_FILTER, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "./fixtures.js"; import { ScheduledEmailDialogStateProvider } from "./ScheduledEmailDialogStateProvider.js"; import { useScheduledExportActions } from "./ScheduledExportActionsContext.js"; import { useScheduledExportDraft } from "./ScheduledExportDraftContext.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateRenderCount.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateRenderCount.test.tsx index 3494c3fd6ec..51c2323093d 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateRenderCount.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/scheduledExportStateRenderCount.test.tsx @@ -37,8 +37,8 @@ vi.mock("../../shared/automationFilters/hooks/useValidateExistingAutomationFilte import { IntlWrapper } from "../../../localization/IntlWrapper.js"; import { AutomationsContextProvider } from "../../contexts/AutomationsContext.js"; import { ScheduledEmailDialogContextProvider } from "../../contexts/ScheduledEmailDialogContext.js"; +import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "../tests/scheduledEmail.test.helpers.js"; -import { AUTOMATIONS_CONTEXT, SCHEDULED_EMAIL_DIALOG_CONTEXT } from "./fixtures.js"; import { ScheduledEmailDialogStateProvider } from "./ScheduledEmailDialogStateProvider.js"; import { useScheduledExportActions } from "./ScheduledExportActionsContext.js"; import { useScheduledExportData } from "./ScheduledExportDataContext.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.test.tsx index e308688ed45..78c8fe3f576 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.test.tsx @@ -58,9 +58,13 @@ vi.mock("../../../../_staging/automation/index.js", () => ({ // --------------------------------------------------------------------------- import * as stagingAutomationModule from "../../../../_staging/automation/index.js"; +import { + makeAutomation, + makeDashboardExportDefinition, + makeWidgetExportDefinition, +} from "../tests/scheduledEmail.test.helpers.js"; import * as exportDefinitionsUtilsModule from "./exportDefinitions.js"; -import { makeAutomation, makeDashboardExportDefinition, makeWidgetExportDefinition } from "./fixtures.js"; import { type IUseScheduledEmailExportSettingsProps, useScheduledEmailExportSettings, @@ -388,6 +392,24 @@ describe("useScheduledEmailExportSettings — per-format settings setters", () = expect(returned.exportDefinitions?.[1].requestPayload.settings).toEqual({ delimiter: "|" }); expect(returned.exportDefinitions?.[0]).toBe(csvDef); }); + + it("onCsvSettingsChange removes the delimiter key instead of writing undefined for Inherit", () => { + const stateBefore = makeAutomation({ exportDefinitions: [csvDef] }); + const returned = applySetter("onCsvSettingsChange", { delimiter: undefined }, stateBefore); + + const settings = returned.exportDefinitions?.[0].requestPayload.settings; + expect(settings).toEqual({}); + expect(settings).not.toHaveProperty("delimiter"); + }); + + it("onCsvRawSettingsChange removes the delimiter key instead of writing undefined for Inherit", () => { + const stateBefore = makeAutomation({ exportDefinitions: [csvRawDef] }); + const returned = applySetter("onCsvRawSettingsChange", { delimiter: undefined }, stateBefore); + + const settings = returned.exportDefinitions?.[0].requestPayload.settings; + expect(settings).toEqual({}); + expect(settings).not.toHaveProperty("delimiter"); + }); }); // --------------------------------------------------------------------------- diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.ts index 2c62957be71..7bf362f85c7 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledEmailExportSettings.ts @@ -282,14 +282,18 @@ export function useScheduledEmailExportSettings({ return exportDefinition; } + const { delimiter: _delimiter, ...restSettings } = + exportDefinition.requestPayload.settings ?? {}; + const nextSettings = + settings.delimiter === undefined + ? restSettings + : { ...restSettings, delimiter: settings.delimiter }; + return { ...exportDefinition, requestPayload: { ...exportDefinition.requestPayload, - settings: { - ...exportDefinition.requestPayload.settings, - delimiter: settings.delimiter, - }, + settings: nextSettings, }, }; }), @@ -307,14 +311,18 @@ export function useScheduledEmailExportSettings({ return exportDefinition; } + const { delimiter: _delimiter, ...restSettings } = + exportDefinition.requestPayload.settings ?? {}; + const nextSettings = + settings.delimiter === undefined + ? restSettings + : { ...restSettings, delimiter: settings.delimiter }; + return { ...exportDefinition, requestPayload: { ...exportDefinition.requestPayload, - settings: { - ...exportDefinition.requestPayload.settings, - delimiter: settings.delimiter, - }, + settings: nextSettings, }, }; }), diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.test.tsx index 9fafd93388c..ed73337d85c 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.test.tsx @@ -15,7 +15,6 @@ import { type IScheduledEmailDialogContextValue, ScheduledEmailDialogContextProvider, } from "../../contexts/ScheduledEmailDialogContext.js"; - import { AUTOMATIONS_CONTEXT, DRAFT_FIXTURE, @@ -25,7 +24,8 @@ import { makeAutomation, makeDashboardExportDefinition, makeWidgetExportDefinition, -} from "./fixtures.js"; +} from "../tests/scheduledEmail.test.helpers.js"; + import { ScheduledExportDraftContextProvider } from "./ScheduledExportDraftContext.js"; import { useScheduledExportAttachments } from "./useScheduledExportAttachments.js"; @@ -118,11 +118,21 @@ describe("useScheduledExportAttachments", () => { expect(result.current.xlsxSettings).toEqual({ mergeHeaders: false, exportInfo: false }); }); - it("csvSettings falls back to the workspace custom delimiter when absent", () => { + it("csvSettings.delimiter stays undefined when no CSV export definition is present, regardless of a workspace default", () => { const { result } = renderAttachments(makeAutomation({ exportDefinitions: [] }), { settings: { exportCsvCustomDelimiter: ";" }, }); + expect(result.current.csvSettings).toEqual({ delimiter: undefined }); + }); + + it("csvSettings reads the delimiter off the present CSV definition", () => { + const { result } = renderAttachments( + makeAutomation({ + exportDefinitions: [makeWidgetExportDefinition("CSV", { settings: { delimiter: ";" } })], + }), + ); + expect(result.current.csvSettings).toEqual({ delimiter: ";" }); }); diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.ts index 018eec4ded5..9565a2a2cc5 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportAttachments.ts @@ -3,7 +3,6 @@ import { useMemo } from "react"; import { - DEFAULT_CSV_DELIMITER, isExportDefinitionDashboardRequestPayload, isExportDefinitionVisualizationObjectRequestPayload, } from "@gooddata/sdk-model"; @@ -31,7 +30,6 @@ export function useScheduledExportAttachments() { const { widget, insight } = useScheduledEmailDialogContext(); const { editedAutomation } = useScheduledExportDraft(); - const resolvedDefaultCsvDelimiter = settings?.exportCsvCustomDelimiter ?? DEFAULT_CSV_DELIMITER; const defaultPdfPageSize = getDefaultPdfPageSize(settings?.formatLocale); const isWidget = !!widget && !!insight; @@ -101,7 +99,7 @@ export function useScheduledExportAttachments() { ? csvExportDefinition.requestPayload.settings : undefined; const csvSettings = { - delimiter: csvExportSettings?.delimiter ?? resolvedDefaultCsvDelimiter, + delimiter: csvExportSettings?.delimiter, }; const csvRawExportDefinition = editedAutomation.exportDefinitions?.find( @@ -115,7 +113,7 @@ export function useScheduledExportAttachments() { ? csvRawExportDefinition.requestPayload.settings : undefined; const csvRawSettings = { - delimiter: csvRawExportSettings?.delimiter ?? resolvedDefaultCsvDelimiter, + delimiter: csvRawExportSettings?.delimiter, }; // Extract templateId per slides format, scoped to the current dialog mode diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportDialogValidity.test.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportDialogValidity.test.tsx index fda06eefc54..5ca87639e65 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportDialogValidity.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/useScheduledExportDialogValidity.test.tsx @@ -44,13 +44,13 @@ import { type IScheduledEmailDialogContextValue, ScheduledEmailDialogContextProvider, } from "../../contexts/ScheduledEmailDialogContext.js"; - import { AUTOMATIONS_CONTEXT, DATA_FIXTURE, DRAFT_FIXTURE, SCHEDULED_EMAIL_DIALOG_CONTEXT, -} from "./fixtures.js"; +} from "../tests/scheduledEmail.test.helpers.js"; + import { ScheduledExportDataContextProvider } from "./ScheduledExportDataContext.js"; import { ScheduledExportDraftContextProvider } from "./ScheduledExportDraftContext.js"; import { useScheduledExportDialogValidity } from "./useScheduledExportDialogValidity.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/fixtures.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/tests/scheduledEmail.test.helpers.ts similarity index 95% rename from libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/fixtures.ts rename to libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/tests/scheduledEmail.test.helpers.ts index ade3ed102ad..fa0118796a7 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/state/fixtures.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/tests/scheduledEmail.test.helpers.ts @@ -19,10 +19,9 @@ import { SENTINEL_CHANNEL as SHARED_SENTINEL_CHANNEL, SENTINEL_WIDGET as SHARED_SENTINEL_WIDGET, WORKSPACE_PARAMETER as SHARED_WORKSPACE_PARAMETER, -} from "../../shared/test/fixtures.js"; - -import { type IScheduledExportDataContextValue } from "./ScheduledExportDataContext.js"; -import { type IScheduledExportDraftContextValue } from "./ScheduledExportDraftContext.js"; +} from "../../tests/shared.test.helpers.js"; +import { type IScheduledExportDataContextValue } from "../state/ScheduledExportDataContext.js"; +import { type IScheduledExportDraftContextValue } from "../state/ScheduledExportDraftContext.js"; export const AUTOMATIONS_CONTEXT = SHARED_AUTOMATIONS_CONTEXT; export const CURRENT_USER = SHARED_CURRENT_USER; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts index 562bdb56f8d..44cbb7e6444 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/scheduledEmail/types.ts @@ -15,15 +15,16 @@ import { type ParameterValue, } from "@gooddata/sdk-model"; import { type GoodDataSdkError } from "@gooddata/sdk-ui"; +import { type ISlotProps } from "@gooddata/sdk-ui-kit"; import { type IAutomationFiltersTab } from "../../../model/store/filtering/types.js"; import { type IAutomationParameter } from "../shared/automationFilters/automationParameters.js"; import { + type IAutomationDialogActionBarProps, type IAutomationDialogDestinationProps, type IAutomationDialogFiltersProps, type IAutomationDialogHeaderProps, type IAutomationDialogRecipientsProps, - type ISlotProps, } from "../shared/slots/types.js"; /// @@ -364,13 +365,13 @@ export interface IScheduledEmailDialogRecipientsProps extends IAutomationDialogR export interface IScheduledEmailDialogSlots { /** * Wraps or replaces the dialog header (the title input row). Must have a stable reference - * identity — see {@link ISlotProps}. + * identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. */ Header?: ComponentType>; /** * Wraps or replaces the Filters tab content (the filter and parameter chips). Must have a - * stable reference identity — see {@link ISlotProps}. + * stable reference identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog **and only while the Filters tab is selected**: * not while the dialog context reports loading, not while the stale-filters confirmation @@ -386,7 +387,7 @@ export interface IScheduledEmailDialogSlots { /** * Wraps or replaces the "Time zone" section on the General tab. Must have a stable reference - * identity — see {@link ISlotProps}. + * identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only when the dialog shows the section at all: the dashboard-timezone feature is * enabled and the dashboard allows the view-mode timezone override. When the section is @@ -396,7 +397,7 @@ export interface IScheduledEmailDialogSlots { /** * Wraps or replaces the dialog's destination region (the notification-channel select on the - * General tab). Must have a stable reference identity — see {@link ISlotProps}. + * General tab). Must have a stable reference identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog **and only while the General tab is selected**: * not while the dialog context reports loading, and not while the stale-filters confirmation @@ -406,13 +407,31 @@ export interface IScheduledEmailDialogSlots { /** * Wraps or replaces the dialog's recipients region on the General tab. Must have a stable - * reference identity — see {@link ISlotProps}. + * reference identity — see {@link @gooddata/sdk-ui-kit#ISlotProps}. * * Renders only in the fully rendered dialog **and only while the General tab is selected**: * not while the dialog context reports loading, and not while the stale-filters confirmation * step is shown. It unmounts — losing any local state — on every switch to the Filters tab. */ Recipients?: ComponentType>; + + /** + * Wraps or replaces the dialog's action bar (the footer row: documentation link, Delete in + * edit mode, Cancel and the submit button). Must have a stable reference identity — see + * {@link @gooddata/sdk-ui-kit#ISlotProps}. + * + * Renders only in the fully rendered dialog: not while the dialog context reports loading + * (the loading dialog keeps its own footer), and not while the stale-filters confirmation + * step is shown. Unlike the Filters and Destination slots it renders on **both** tabs — the + * footer is tab-independent. + * + * A replacement that does not render `Default` loses the submit button's Enter-key detection + * id (Enter no longer submits), the validation aria wiring, and the default row's ordering. + * Wraps that render `` keep everything; note the Enter-key path + * invokes the dialog's own submit handler and disabled state, so `defaultProps` overrides + * affect the buttons only. + */ + ActionBar?: ComponentType>; } /** @@ -434,7 +453,7 @@ export interface IDefaultScheduledEmailDialogProps extends IScheduledEmailDialog * * @example * The dialog is reached through the `Dashboard` component override; define slot components at - * module scope (see {@link ISlotProps}): + * module scope (see {@link @gooddata/sdk-ui-kit#ISlotProps}): * ```tsx * function RecipientsWithNote({ Default, defaultProps }: ISlotProps) { * return ( @@ -453,6 +472,21 @@ export interface IDefaultScheduledEmailDialogProps extends IScheduledEmailDialog * ``` */ slots?: IScheduledEmailDialogSlots; + + /** + * Content rendered as the first child of the dialog's scrollable content area, above the + * form. Rendered only in the fully rendered dialog: not while the dialog context reports + * loading, and not while the stale-filters confirmation step is shown. Rendered on both + * tabs — it is a content-area child, not a tab child. + */ + topContent?: ReactNode; + + /** + * Content rendered as the last child of the dialog's scrollable content area, below the + * form. Same rendering conditions as {@link IDefaultScheduledEmailDialogProps.topContent}. + * Rendered on both tabs — it is a content-area child, not a tab child. + */ + bottomContent?: ReactNode; } /** diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/automationParameters.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/automationParameters.test.ts index c91068eabc1..809fa01ffd1 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/automationParameters.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/automationParameters.test.ts @@ -6,6 +6,12 @@ import { describe, expect, it } from "vitest"; import { idRef } from "@gooddata/sdk-model"; +import { + dashboardParameter, + workspaceNumberParameter, + workspaceStringParameter, +} from "../../tests/parameterFixtures.test.helpers.js"; + import { type IAutomationParameter, automationParametersToExportParameters, @@ -15,11 +21,6 @@ import { reconstructAutomationParametersFromExportParameters, reconstructAutomationParametersFromValues, } from "./automationParameters.js"; -import { - dashboardParameter, - workspaceNumberParameter, - workspaceStringParameter, -} from "./parameterFixtures.js"; describe("availableAutomationParameters — addable workspace parameters", () => { const catalog = [ diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.alertParameters.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.alertParameters.test.ts index b7ebb832d6f..4528d0ccb40 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.alertParameters.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/useValidateExistingAutomationFilters.alertParameters.test.ts @@ -10,7 +10,7 @@ import { idRef, } from "@gooddata/sdk-model"; -import { workspaceNumberParameter } from "../parameterFixtures.js"; +import { workspaceNumberParameter } from "../../../tests/parameterFixtures.test.helpers.js"; import { useValidateExistingAutomationFilters } from "./useValidateExistingAutomationFilters.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/validateExistingAutomationParameters.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/validateExistingAutomationParameters.test.ts index 96981eae873..75bdf4296d0 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/validateExistingAutomationParameters.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/hooks/validateExistingAutomationParameters.test.ts @@ -8,7 +8,7 @@ import { dashboardParameter, workspaceNumberParameter, workspaceStringParameter, -} from "../parameterFixtures.js"; +} from "../../../tests/parameterFixtures.test.helpers.js"; import { validateExistingAutomationParameters } from "./useValidateExistingAutomationFilters.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationAlertParameters.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationAlertParameters.test.ts index a4500423f54..87a3873d8dc 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationAlertParameters.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationAlertParameters.test.ts @@ -17,7 +17,8 @@ import { dashboardParameter, workspaceNumberParameter, workspaceStringParameter, -} from "./parameterFixtures.js"; +} from "../../tests/parameterFixtures.test.helpers.js"; + import { useAutomationAlertParameters } from "./useAutomationAlertParameters.js"; interface IMockContextState { diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationExportParameters.test.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationExportParameters.test.ts index a5ee0abc361..5b17ba70786 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationExportParameters.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/useAutomationExportParameters.test.ts @@ -12,12 +12,12 @@ import { } from "@gooddata/sdk-model"; import type { ExtendedDashboardWidget } from "../../../../model/types/layoutTypes.js"; - import { dashboardParameter, workspaceNumberParameter, workspaceStringParameter, -} from "./parameterFixtures.js"; +} from "../../tests/parameterFixtures.test.helpers.js"; + import { type IUseAutomationExportParametersProps, useAutomationExportParameters, diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/AutomationDialogActionBar.tsx b/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/AutomationDialogActionBar.tsx new file mode 100644 index 00000000000..be4d6a14187 --- /dev/null +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/AutomationDialogActionBar.tsx @@ -0,0 +1,86 @@ +// (C) 2026 GoodData Corporation + +import { Button, ConfirmDialogFooter, Hyperlink } from "@gooddata/sdk-ui-kit"; + +import { type IAutomationDialogActionBarProps } from "./types.js"; + +interface IAutomationDialogFooterLeftProps { + helpLinkText?: string; + helpLinkHref?: string; + deleteButtonText?: string; + onDelete?: () => void; + isDeleteDisabled?: boolean; +} + +/** + * The footer-left area of both automation dialogs: the documentation link and, in edit mode, + * the delete button. + * + * @internal + */ +export function AutomationDialogFooterLeft({ + helpLinkText, + helpLinkHref, + deleteButtonText, + onDelete, + isDeleteDisabled, +}: IAutomationDialogFooterLeftProps) { + return ( +
+ {helpLinkText && helpLinkHref ? ( + + ) : null} + {onDelete ? ( +
+ ); +} + +/** + * Default implementation of both automation dialogs' ActionBar slot. Fully props-driven: every + * value it renders arrives through {@link IAutomationDialogActionBarProps}, so a wrapping slot + * can override any of them before spreading onto it. + * + * @internal + */ +export function AutomationDialogActionBar({ + cancelButtonText, + submitButtonText, + onCancel, + onSubmit, + isSubmitDisabled, + isSaving, + submitButtonTooltipText, + helpLinkText, + helpLinkHref, + onDelete, + deleteButtonText, +}: IAutomationDialogActionBarProps) { + return ( + + } + showProgressIndicator={isSaving} + cancelButtonText={cancelButtonText} + onCancel={onCancel} + submitButtonText={submitButtonText} + onSubmit={onSubmit} + isSubmitDisabled={isSubmitDisabled} + submitButtonTooltipText={submitButtonTooltipText} + isPositive + /> + ); +} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/types.ts b/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/types.ts index 5d5bfe22e6e..fb3a6917ed9 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/types.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/shared/slots/types.ts @@ -1,6 +1,6 @@ // (C) 2026 GoodData Corporation -import { type ComponentType, type ReactNode } from "react"; +import { type ReactNode } from "react"; import { type FilterContextItem, @@ -13,33 +13,6 @@ import { import { type IAutomationParameter } from "../automationFilters/automationParameters.js"; -/** - * Contract of a section-level slot: the default implementation and the exact props the default - * dialog would render it with. - * - * The component a customer assigns to a slot is rendered as an element type, so its reference - * identity is load-bearing: define it at module scope (or memoize it), never inline in a render - * function — an inline definition gets a fresh identity on every render of the declaring - * component, which unmounts and remounts the region, losing focus and transient DOM state. - * - * Render `` inside your own markup to wrap the region rather than - * replace it; a slot that does not spread `defaultProps` onto `Default` loses the default - * behavior wired through them (including the dialog's initial-focus ref). - * - * @alpha - */ -export interface ISlotProps { - /** - * The default implementation of the region. - */ - Default: ComponentType; - - /** - * The exact props the default dialog would render {@link ISlotProps.Default} with. - */ - defaultProps: TProps; -} - /** * Members shared by both automation dialogs' header regions. * @@ -203,3 +176,66 @@ export interface IAutomationDialogRecipientsProps { */ externalRecipientOverride?: string; } + +/** + * Members shared by both automation dialogs' action-bar regions (the footer row). + * + * @alpha + */ +export interface IAutomationDialogActionBarProps { + /** + * Label of the cancel button. + */ + cancelButtonText: string; + + /** + * Label of the submit button ("Create" / "Save" per mode). + */ + submitButtonText: string; + + /** + * Closes the dialog without saving. + */ + onCancel: () => void; + + /** + * Submits the automation. + */ + onSubmit: () => void; + + /** + * Whether submitting is currently disabled (validation, saving, execution-timestamp mode). + */ + isSubmitDisabled: boolean; + + /** + * Whether a save is in flight; drives the progress spinner and disables Delete. + */ + isSaving: boolean; + + /** + * Tooltip shown on the disabled submit button, when there is one. + */ + submitButtonTooltipText?: string; + + /** + * Text of the documentation link. Absent (with {@link IAutomationDialogActionBarProps.helpLinkHref}) + * when the workspace is white-labeled. + */ + helpLinkText?: string; + + /** + * Target of the documentation link. Absent when the workspace is white-labeled. + */ + helpLinkHref?: string; + + /** + * Opens the delete confirmation. Absent when creating a new automation. + */ + onDelete?: () => void; + + /** + * Label of the delete button. Present with {@link IAutomationDialogActionBarProps.onDelete}. + */ + deleteButtonText?: string; +} diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/parameterFixtures.ts b/libs/sdk-ui-dashboard/src/presentation/automations/tests/parameterFixtures.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/presentation/automations/shared/automationFilters/parameterFixtures.ts rename to libs/sdk-ui-dashboard/src/presentation/automations/tests/parameterFixtures.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/presentation/automations/shared/test/fixtures.ts b/libs/sdk-ui-dashboard/src/presentation/automations/tests/shared.test.helpers.ts similarity index 95% rename from libs/sdk-ui-dashboard/src/presentation/automations/shared/test/fixtures.ts rename to libs/sdk-ui-dashboard/src/presentation/automations/tests/shared.test.helpers.ts index c5a6f67eb04..bb442dd29ec 100644 --- a/libs/sdk-ui-dashboard/src/presentation/automations/shared/test/fixtures.ts +++ b/libs/sdk-ui-dashboard/src/presentation/automations/tests/shared.test.helpers.ts @@ -8,8 +8,9 @@ import { idRef, } from "@gooddata/sdk-model"; -import { type IAutomationsContextValue } from "../../contexts/AutomationsContext.js"; -import { workspaceStringParameter } from "../automationFilters/parameterFixtures.js"; +import { type IAutomationsContextValue } from "../contexts/AutomationsContext.js"; + +import { workspaceStringParameter } from "./parameterFixtures.test.helpers.js"; export const CURRENT_USER: IUser = { ref: idRef("user-1"), diff --git a/libs/sdk-ui-dashboard/src/presentation/dashboard/DashboardHeader/DashboardHeader.test.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboard/DashboardHeader/DashboardHeader.test.tsx index 041a7af1561..01416bf86d7 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dashboard/DashboardHeader/DashboardHeader.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dashboard/DashboardHeader/DashboardHeader.test.tsx @@ -4,7 +4,7 @@ import { screen } from "@testing-library/react"; import { PointerEventsCheckLevel, userEvent } from "@testing-library/user-event"; import { describe, expect, it } from "vitest"; -import { render } from "../../../../test/render.js"; +import { render } from "../tests/render.test.utils.js"; import { DashboardTabsWrapper } from "./DashboardHeader.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardLoading.test.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardLoading.test.tsx index 6f2d539c9f5..3084cbfe748 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardLoading.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardLoading.test.tsx @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; -import { render } from "../../../../test/render.js"; +import { render } from "../tests/render.test.utils.js"; import { DashboardLoading } from "./DashboardLoading.js"; diff --git a/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardMainContent.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardMainContent.tsx deleted file mode 100644 index bb814f57c6a..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/dashboard/components/DashboardMainContent.tsx +++ /dev/null @@ -1,67 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { type Ref, type RefObject, forwardRef, useEffect } from "react"; - -import cx from "classnames"; - -import { changeFilterContextSelection } from "../../../model/commands/filters.js"; -import { useDispatchDashboardCommand } from "../../../model/react/useDispatchDashboardCommand.js"; -import { useWidgetSelection } from "../../../model/react/useWidgetSelection.js"; -import { useDashboardDrop } from "../../dragAndDrop/useDashboardDrop.js"; -import { useWidgetDragHoverHandlers as useFlexibleWidgetDragHoverHandlers } from "../../flexibleLayout/dragAndDrop/draggableWidget/useWidgetDragHoverHandlers.js"; -import { DashboardLayout } from "../../widget/dashboardLayout/DashboardLayout.js"; -import { type IDashboardProps } from "../types.js"; - -import { DateFilterConfigWarnings } from "./DateFilterConfigWarnings.js"; - -export const DashboardMainContent = forwardRef(function DashboardMainContent(_: IDashboardProps, ref) { - const onFiltersChange = useDispatchDashboardCommand(changeFilterContextSelection); - const { deselectWidgets } = useWidgetSelection(); - const useWidgetDragHoverHandlers = useFlexibleWidgetDragHoverHandlers; - const { handleDragHoverEnd } = useWidgetDragHoverHandlers(); - const [{ isOver }, dropRef] = useDashboardDrop( - [ - "insight", - "insight-placeholder", - "insightListItem", - "kpi", - "kpi-placeholder", - "richText", - "richTextListItem", - "visualizationSwitcher", - "visualizationSwitcherListItem", - "dashboardLayout", - "dashboardLayoutListItem", - ], - {}, - ); - - useEffect(() => { - if (!isOver) { - handleDragHoverEnd(); - } - }, [handleDragHoverEnd, isOver]); - - const classNames = cx( - "gd-flex-container", - "root-flex-maincontent", - "gd-grid-layout", - "gd-auto-resized-dashboard-descriptions", - ); - - return ( -
} - > -
| undefined} - onClick={deselectWidgets} - > - - -
-
- ); -}); diff --git a/libs/sdk-ui-dashboard/test/render.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboard/tests/render.test.utils.tsx similarity index 92% rename from libs/sdk-ui-dashboard/test/render.tsx rename to libs/sdk-ui-dashboard/src/presentation/dashboard/tests/render.test.utils.tsx index ed87ff293d2..8e648a082a6 100644 --- a/libs/sdk-ui-dashboard/test/render.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dashboard/tests/render.test.utils.tsx @@ -14,9 +14,9 @@ import { Provider } from "react-redux"; import { dummyBackend } from "@gooddata/sdk-backend-base"; -import { type DashboardState, ReactDashboardContext } from "../src/index.js"; -import { createDashboardRootReducer, createDashboardStore } from "../src/model/store/dashboardStore.js"; -import { IntlWrapper } from "../src/presentation/localization/IntlWrapper.js"; +import { type DashboardState, ReactDashboardContext } from "../../../index.js"; +import { createDashboardRootReducer, createDashboardStore } from "../../../model/store/dashboardStore.js"; +import { IntlWrapper } from "../../localization/IntlWrapper.js"; type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial } : T; diff --git a/libs/sdk-ui-dashboard/src/presentation/dashboardContexts/ExportCsvDialogContext.tsx b/libs/sdk-ui-dashboard/src/presentation/dashboardContexts/ExportCsvDialogContext.tsx index 8017621bd8f..6a17fb72f15 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dashboardContexts/ExportCsvDialogContext.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dashboardContexts/ExportCsvDialogContext.tsx @@ -3,11 +3,10 @@ import { type ReactNode, createContext, useCallback, useContext, useMemo, useState } from "react"; export interface IExportCsvDialogData { - delimiter: string; + delimiter?: string; } export interface IExportCsvDialogConfig { - initialDelimiter?: string; onSubmit: (data: IExportCsvDialogData) => void; } diff --git a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.test.tsx b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.test.tsx index 219a6f06459..33f9285e15b 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.test.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.test.tsx @@ -42,23 +42,10 @@ function getPreviewChar(optionId: string): HTMLElement | null { } describe("ExportCsvDialog", () => { - it("should initialize from the resolved default delimiter", () => { - renderComponent({ initialDelimiter: ";" }); - - expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Semicolon"); - }); - - it("should initialize custom delimiter when the resolved default is custom", () => { - renderComponent({ initialDelimiter: "^" }); - - expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Custom"); - expect(getCustomInput()).toHaveValue("^"); - }); - - it("should default to comma when no resolved delimiter is provided", () => { + it("should default to inherit when no resolved delimiter is provided", () => { renderComponent(); - expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Comma"); + expect(document.querySelector(".s-csv-delimiter-dropdown")).toHaveTextContent("Inherit"); }); it("should render delimiter previews separately from the label", () => { diff --git a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.tsx b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.tsx index 6d9c6174968..487b88e00ed 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialog.tsx @@ -24,18 +24,13 @@ const messages = defineMessages({ }); export interface IExportCsvDialogProps { - initialDelimiter?: string; onCancel: () => void; onSubmit: (data: IExportCsvDialogData) => void; } -export const ExportCsvDialog = memo(function ExportCsvDialog({ - initialDelimiter, - onCancel, - onSubmit, -}: IExportCsvDialogProps) { +export const ExportCsvDialog = memo(function ExportCsvDialog({ onCancel, onSubmit }: IExportCsvDialogProps) { const intl = useIntl(); - const [value, setValue] = useState(() => getCsvDelimiterState(initialDelimiter)); + const [value, setValue] = useState(() => getCsvDelimiterState()); const validationContextValue = useValidationContextValue(createInvalidNode()); const validationError = diff --git a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialogProvider.tsx b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialogProvider.tsx index b7542f7d604..553b6f8e167 100644 --- a/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialogProvider.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/dialogs/ExportCsvDialogProvider.tsx @@ -12,7 +12,6 @@ export function ExportCsvDialogProvider() { return isOpen && dialogConfig ? ( { closeDialog(); diff --git a/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/DraggableKpiCreatePanelItem.tsx b/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/DraggableKpiCreatePanelItem.tsx deleted file mode 100644 index 883e99a4aeb..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/DraggableKpiCreatePanelItem.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { KPI_WIDGET_SIZE_INFO_DEFAULT } from "@gooddata/sdk-ui-ext"; - -import { type CustomCreatePanelItemComponent } from "../../componentDefinition/types.js"; -import { DraggableCreatePanelItem } from "../DraggableCreatePanelItem.js"; -import { type DraggableItem, type IWrapCreatePanelItemWithDragComponent } from "../types.js"; - -/** - * @internal - */ -interface IDraggableKpiCreatePanelItemProps { - CreatePanelItemComponent: CustomCreatePanelItemComponent; - WrapCreatePanelItemWithDragComponent?: IWrapCreatePanelItemWithDragComponent; - disabled?: boolean; -} - -const dragItem: DraggableItem = { - type: "kpi-placeholder", - size: { - gridHeight: KPI_WIDGET_SIZE_INFO_DEFAULT.height.default, - gridWidth: KPI_WIDGET_SIZE_INFO_DEFAULT.width.default, - }, -}; - -/** - * @internal - */ -export function DraggableKpiCreatePanelItem({ - CreatePanelItemComponent, - WrapCreatePanelItemWithDragComponent, - disabled, -}: IDraggableKpiCreatePanelItemProps) { - return ( - - ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/KpiDraggingComponent.tsx b/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/KpiDraggingComponent.tsx deleted file mode 100644 index effcbb7ac4d..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/dragAndDrop/draggableWidget/KpiDraggingComponent.tsx +++ /dev/null @@ -1,16 +0,0 @@ -// (C) 2022-2025 GoodData Corporation - -import { ShortenedText } from "@gooddata/sdk-ui-kit"; - -import { type IKpiDraggingComponentProps } from "../../componentDefinition/types.js"; - -/* - * @internal - */ -export function KpiDraggingComponent({ item }: IKpiDraggingComponentProps) { - return ( -
- {item.title} -
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/DeleteButton.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/DeleteButton.tsx deleted file mode 100644 index 2bef60183d6..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/DeleteButton.tsx +++ /dev/null @@ -1,29 +0,0 @@ -// (C) 2021-2025 GoodData Corporation - -import { FormattedMessage } from "react-intl"; - -import { Bubble, BubbleHoverTrigger, Button, type IAlignPoint } from "@gooddata/sdk-ui-kit"; - -interface IDeleteButton { - deleteFilter: () => void; -} - -const bubbleAlignPoints: IAlignPoint[] = [{ align: "bc tc", offset: { x: -1, y: 5 } }]; - -export function DeleteButton({ deleteFilter }: IDeleteButton) { - return ( -
- -
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/common/DropdownControls.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/common/DropdownControls.tsx deleted file mode 100644 index 11fe21ac7e1..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/common/DropdownControls.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// (C) 2022-2025 GoodData Corporation - -import { useIntl } from "react-intl"; - -import { Button } from "@gooddata/sdk-ui-kit"; - -interface IConfigurationPanelControlsProps { - closeHandler: () => void; - onSave: () => void; - isSaveButtonEnabled: boolean; -} - -export function DropdownControls({ - closeHandler, - isSaveButtonEnabled, - onSave, -}: IConfigurationPanelControlsProps) { - const intl = useIntl(); - - const onSaveHandler = () => { - onSave(); - closeHandler(); - }; - - return ( -
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/ConfigurationButton.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/ConfigurationButton.tsx deleted file mode 100644 index 55da132c157..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/configuration/ConfigurationButton.tsx +++ /dev/null @@ -1,26 +0,0 @@ -// (C) 2021-2025 GoodData Corporation - -import { FormattedMessage } from "react-intl"; - -interface IConfigurationButton { - setIsConfigurationOpen: (isOpen: boolean) => void; -} - -export function ConfigurationButton({ setIsConfigurationOpen }: IConfigurationButton) { - return ( -
-
{ - setIsConfigurationOpen(true); - }} - > -
- - - -
-
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/displayFormDropdown/DisplayFormButton.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/displayFormDropdown/DisplayFormButton.tsx deleted file mode 100644 index 1355e29ce78..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/attributeFilter/dashboardDropdownBody/displayFormDropdown/DisplayFormButton.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// (C) 2021-2025 GoodData Corporation - -import { type SyntheticEvent } from "react"; - -import classNames from "classnames"; - -import { Button } from "@gooddata/sdk-ui-kit"; - -export interface IToggleButtonProps { - text: string; - isOpened: boolean; - toggleDropdown: (e: SyntheticEvent) => void; -} - -export function DisplayFormButton({ isOpened, text: title, toggleDropdown }: IToggleButtonProps) { - const buttonClassNames = classNames( - "gd-button-primary", - "gd-button-small", - "button-dropdown", - "dropdown-button", - "attribute-display-form-button", - "s-attribute-display-form-button", - { - "is-active": isOpened, - }, - ); - const iconRight = isOpened ? "icon-navigateup" : "icon-navigatedown"; - return ( -
-
-
- - - -
- -
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorItem.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorItem.tsx deleted file mode 100644 index 3471f8244bd..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorItem.tsx +++ /dev/null @@ -1,25 +0,0 @@ -// (C) 2019-2025 GoodData Corporation - -import { type IAvailableDrillTargetMeasure } from "@gooddata/sdk-ui"; - -export interface IDrillMeasureSelectorItemProps { - item: IAvailableDrillTargetMeasure; - onClick: (item: IAvailableDrillTargetMeasure) => void; -} - -export function DrillMeasureSelectorItem(props: IDrillMeasureSelectorItemProps) { - const onClick = () => { - props.onClick(props.item); - }; - - const name = props.item.measure.measureHeaderItem.name; - return ( - - {name} - - ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorList.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorList.tsx deleted file mode 100644 index f1e362cb272..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/DrillMeasureSelector/DrillMeasureSelectorList.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// (C) 2019-2025 GoodData Corporation - -import { type IAvailableDrillTargetMeasure } from "@gooddata/sdk-ui"; - -import { DrillMeasureSelectorItem } from "./DrillMeasureSelectorItem.js"; - -export interface IDrillMeasureSelectorListProps { - supportedItems: IAvailableDrillTargetMeasure[]; - onSelect: (item: IAvailableDrillTargetMeasure) => void; -} - -export function DrillMeasureSelectorList(props: IDrillMeasureSelectorListProps) { - return ( -
- {props.supportedItems.map((item) => ( - - ))} -
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/AlertTitle.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/AlertTitle.tsx deleted file mode 100644 index 76f667fc56d..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/AlertTitle.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// (C) 2025-2026 GoodData Corporation - -import { useIntl } from "react-intl"; - -import { type IAutomationMetadataObject, type ISeparators } from "@gooddata/sdk-model"; -import { type IInputPureProps, Input } from "@gooddata/sdk-ui-kit"; - -import { getDescription } from "../../../../automations/alerting/DefaultAlertingDialog/utils/getters.js"; -import { type AlertMetric } from "../../../../automations/alerting/types.js"; - -export interface IAlertTitleProps { - id?: string; - measures: AlertMetric[]; - alert: IAutomationMetadataObject | undefined; - separators?: ISeparators; - onChange: IInputPureProps["onChange"]; -} - -export function AlertTitle({ id, alert, measures, separators, onChange }: IAlertTitleProps) { - const intl = useIntl(); - const description = getDescription(intl, measures, alert, separators); - - return ( - - ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/CreateAlert.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/CreateAlert.tsx deleted file mode 100644 index 6376039bc07..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/CreateAlert.tsx +++ /dev/null @@ -1,77 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { - type IAutomationMetadataObject, - type IAutomationMetadataObjectDefinition, - type ICatalogAttribute, - type ICatalogDateDataset, - type INotificationChannelIdentifier, - type INotificationChannelMetadataObject, - type ISeparators, -} from "@gooddata/sdk-model"; - -import { type IExecutionResultEnvelope } from "../../../../../model/store/executionResults/types.js"; -import { type IMeasureFormatMap } from "../../../../automations/alerting/DefaultAlertingDialog/utils/getters.js"; -import { type AlertAttribute, type AlertMetric } from "../../../../automations/alerting/types.js"; - -import { EditAlert } from "./EditAlert.js"; - -interface ICreateAlertProps { - execResult: IExecutionResultEnvelope | undefined; - alert: IAutomationMetadataObjectDefinition | null; - onClose: () => void; - onCancel: () => void; - onCreate?: (alert: IAutomationMetadataObjectDefinition) => void; - destinations: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; - hasAlerts: boolean; - measures: AlertMetric[]; - attributes: AlertAttribute[]; - maxAutomationsReached: boolean; - maxAutomationsRecipients: number; - measureFormatMap: IMeasureFormatMap; - catalogAttributes: ICatalogAttribute[]; - catalogDateDatasets: ICatalogDateDataset[]; - separators?: ISeparators; - isExecutionTimestampMode?: boolean; -} - -export function CreateAlert({ - execResult, - alert, - onClose, - onCancel, - onCreate, - destinations, - hasAlerts, - measures, - attributes, - maxAutomationsReached, - maxAutomationsRecipients, - measureFormatMap, - catalogAttributes, - catalogDateDatasets, - separators, - isExecutionTimestampMode, -}: ICreateAlertProps) { - return ( - - ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.tsx deleted file mode 100644 index 2509d2fae00..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.tsx +++ /dev/null @@ -1,499 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { FormattedMessage, type MessageDescriptor, defineMessages, useIntl } from "react-intl"; - -import { - type IAutomationMetadataObject, - type IAutomationMetadataObjectDefinition, - type ICatalogAttribute, - type ICatalogDateDataset, - type IInsightWidget, - type INotificationChannelIdentifier, - type INotificationChannelMetadataObject, - type ISeparators, -} from "@gooddata/sdk-model"; -import { - Bubble, - BubbleHoverTrigger, - Button, - Input, - Message, - type OverlayPositionType, -} from "@gooddata/sdk-ui-kit"; - -import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js"; -import { type IExecutionResultEnvelope } from "../../../../../model/store/executionResults/types.js"; -import { selectInsightByWidgetRef } from "../../../../../model/store/insights/insightsSelectors.js"; -import { selectWidgets } from "../../../../../model/store/tabs/layout/layoutSelectors.js"; -import { AlertAttributeSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertAttributeSelect.js"; -import { AlertComparisonOperatorSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertComparisonOperatorSelect.js"; -import { AlertComparisonPeriodSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertComparisonPeriodSelect.js"; -import { AlertDestinationSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertDestinationSelect.js"; -import { AlertGranularitySelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertGranularitySelect.js"; -import { AlertMeasureSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertMeasureSelect.js"; -import { AlertSensitivitySelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertSensitivitySelect.js"; -import { - type AlertInvalidityReason, - useAlertValidation, -} from "../../../../automations/alerting/DefaultAlertingDialog/hooks/useAlertValidation.js"; -import { useAttributeValuesFromExecResults } from "../../../../automations/alerting/DefaultAlertingDialog/hooks/useAttributeValuesFromExecResults.js"; -import { useThresholdValue } from "../../../../automations/alerting/DefaultAlertingDialog/hooks/useThresholdValue.js"; -import { - type IMeasureFormatMap, - getAlertAiOperator, - getAlertAttribute, - getAlertCompareOperator, - getAlertComparison, - getAlertFilters, - getAlertGranularity, - getAlertMeasure, - getAlertRelativeOperator, - getAlertSensitivity, - getValueSuffix, -} from "../../../../automations/alerting/DefaultAlertingDialog/utils/getters.js"; -import { translateGranularity } from "../../../../automations/alerting/DefaultAlertingDialog/utils/granularity.js"; -import { - isAnomalyDetection, - isChangeOrDifferenceOperator, -} from "../../../../automations/alerting/DefaultAlertingDialog/utils/guards.js"; -import { type AlertAttribute, type AlertMetric } from "../../../../automations/alerting/types.js"; -import { RecipientsSelect } from "../../../../automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.js"; -import { DashboardInsightSubmenuContainer } from "../../../insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/DashboardInsightSubmenuContainer.js"; - -import { AlertTitle } from "./AlertTitle.js"; -import { EditAlertConfiguration } from "./EditAlertConfiguration.js"; -import { useEditAlert } from "./hooks/useEditAlert.js"; - -const TOOLTIP_ALIGN_POINTS = [{ align: "cl cr" }, { align: "cr cl" }]; - -const messages = defineMessages({ - invalidDefault: { - id: "insightAlert.config.invalid", - }, - invalidWidget: { - id: "insightAlert.config.invalidWidget", - }, -}); - -const invalidMessagesObj: Record = { - missingMetric: messages.invalidDefault, - missingWidget: messages.invalidWidget, -}; - -interface IEditAlertProps { - execResult: IExecutionResultEnvelope | undefined; - alert: IAutomationMetadataObject; - isNewAlert?: boolean; - hasAlerts: boolean; - destinations: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; - measures: AlertMetric[]; - attributes: AlertAttribute[]; - measureFormatMap: IMeasureFormatMap; - catalogAttributes: ICatalogAttribute[]; - catalogDateDatasets: ICatalogDateDataset[]; - onClose: () => void; - onCancel: () => void; - onCreate?: (alert: IAutomationMetadataObjectDefinition) => void; - onUpdate?: (alert: IAutomationMetadataObject) => void; - maxAutomationsReached?: boolean; - maxAutomationsRecipients: number; - overlayPositionType?: OverlayPositionType; - separators?: ISeparators; - isExecutionTimestampMode?: boolean; -} - -export function EditAlert({ - alert, - execResult, - isNewAlert, - hasAlerts, - destinations, - attributes, - measures, - onClose, - onCancel, - onCreate, - onUpdate, - maxAutomationsReached = false, - maxAutomationsRecipients, - overlayPositionType, - measureFormatMap, - catalogAttributes, - catalogDateDatasets, - separators, - isExecutionTimestampMode, -}: IEditAlertProps) { - const { - defaultUser, - viewMode, - updatedAlert, - canSubmit, - allowExternalRecipients, - allowOnlyLoggedUserRecipients, - warningMessage, - enableAnomalyDetectionAlert, - allowHourlyRecurrence, - // - changeAnomalyDetection, - changeComparisonOperator, - changeRelativeOperator, - changeMeasure, - changeAttribute, - changeTitle, - changeValue, - changeDestination, - changeComparisonType, - changeRecipients, - changeSensitivity, - changeGranularity, - // - configureAlert, - saveAlertConfiguration, - cancelAlertConfiguration, - // - createAlert, - updateAlert, - } = useEditAlert({ - metrics: measures, - separators, - attributes, - alert, - onCreate, - onUpdate, - measureFormatMap, - catalogAttributes, - catalogDateDatasets, - destinations, - }); - const intl = useIntl(); - const disableCreateButtonDueToLimits = isNewAlert && maxAutomationsReached; - const selectedMeasure = getAlertMeasure(measures, updatedAlert.alert); - const selectedComparator = getAlertComparison(selectedMeasure, updatedAlert.alert); - const [selectedAttribute, selectedValue] = getAlertAttribute(attributes, updatedAlert); - const filters = getAlertFilters(updatedAlert); - const selectedComparisonOperator = getAlertCompareOperator(updatedAlert.alert); - const selectedRelativeOperator = getAlertRelativeOperator(updatedAlert.alert); - const selectedAiOperator = getAlertAiOperator(updatedAlert.alert); - const selectedSensitivity = getAlertSensitivity(updatedAlert.alert); - const selectedGranularity = getAlertGranularity(updatedAlert.alert); - - const widgetLocalId = alert?.metadata?.widget; - const allWidgets = useDashboardSelector(selectWidgets); - const alertWidget = widgetLocalId - ? allWidgets.find((w) => w.localIdentifier === widgetLocalId) - : undefined; - const alertInsight = useDashboardSelector(selectInsightByWidgetRef(alertWidget?.ref)); - const { isValid, invalidityReason } = useAlertValidation( - alert, - alertWidget as IInsightWidget | undefined, - alertInsight, - catalogDateDatasets, - isNewAlert, - ); - const showFilterInfo = filters.length > 0 || Boolean(selectedComparator?.granularity); - - const { isResultLoading, getAttributeValues, getMetricValue } = - useAttributeValuesFromExecResults(execResult); - - const { value, onChange, onBlur } = useThresholdValue( - changeValue, - getMetricValue, - isNewAlert, - updatedAlert.alert, - selectedRelativeOperator, - selectedMeasure, - selectedAttribute, - selectedValue, - ); - - return viewMode === "edit" ? ( - -
-
-
- - - - - {showFilterInfo ? ( -
- {Boolean(selectedComparator?.granularity) && ( - - )} - {filters.length > 0 && selectedComparator?.granularity ? ( - - ) : null} - {filters.length > 0 && ( - <> - -
- -
- - - ), - }} - /> - - -
- - )} -
- ) : null} - - {!isAnomalyDetection(updatedAlert?.alert) && - (() => { - const valueSuffix = getValueSuffix(updatedAlert.alert); - const suffixAriaLabel = - valueSuffix === "%" - ? intl.formatMessage({ id: "input.unit.percent" }) - : valueSuffix; - - return ( - - ); - })()} - {!updatedAlert || !isChangeOrDifferenceOperator(updatedAlert.alert) ? null : ( -
- - { - changeComparisonType( - selectedMeasure, - selectedRelativeOperator, - comparisonType, - granularity, - ); - }} - overlayPositionType={overlayPositionType} - /> -
- )} - {!updatedAlert || !isAnomalyDetection(updatedAlert.alert) ? null : ( - <> -
- - -
-
- - { - changeGranularity(selectedMeasure, granularity); - }} - overlayPositionType={overlayPositionType} - /> -
- - )} - {destinations.length > 1 && ( -
- - -
- )} - - - { - changeTitle(e === "" ? undefined : String(e)); - }} - /> -
- {warningMessage ? {warningMessage} : null} - {isValid ? null : ( - - - - )} -
-
- - - - {disableCreateButtonDueToLimits ? ( - - - - ) : null} - {isExecutionTimestampMode ? ( - - - - ) : null} - -
-
-
-
- ) : ( - - - - ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlertConfiguration.tsx b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlertConfiguration.tsx deleted file mode 100644 index 80e6d388b71..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/EditAlertConfiguration.tsx +++ /dev/null @@ -1,104 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { useState } from "react"; - -import { FormattedMessage } from "react-intl"; - -import { type IAutomationMetadataObject } from "@gooddata/sdk-model"; -import { - Bubble, - BubbleHoverTrigger, - Button, - IconQuestionMark, - type OverlayPositionType, -} from "@gooddata/sdk-ui-kit"; -import { useTheme } from "@gooddata/sdk-ui-theme-provider"; - -import { AlertTriggerModeSelect } from "../../../../automations/alerting/DefaultAlertingDialog/components/AlertTriggerModeSelect.js"; -import { gdColorStateBlank } from "../../../../constants/colors.js"; - -const TOOLTIP_ALIGN_POINTS = [ - { align: "cr cl", offset: { x: 0, y: -1 } }, - { align: "cl cr", offset: { x: 0, y: -1 } }, -]; - -interface IEditAlertConfigurationProps { - alert: IAutomationMetadataObject; - onCancel: () => void; - onUpdate: (alert: IAutomationMetadataObject) => void; - overlayPositionType?: OverlayPositionType; -} - -export function EditAlertConfiguration({ - alert, - onCancel, - onUpdate, - overlayPositionType, -}: IEditAlertConfigurationProps) { - const [updatedAlert, setUpdatedAlert] = useState(alert); - const canSubmit = updatedAlert.alert?.trigger.mode !== alert.alert?.trigger.mode; - const theme = useTheme(); - - const accessibilityValue = "alert.configuration.trigger"; - - return ( -
-
- -
- { - setUpdatedAlert({ - ...updatedAlert, - alert: { - ...updatedAlert.alert!, - trigger: { - ...updatedAlert.alert!.trigger, - mode: triggerMode, - }, - }, - }); - }} - overlayPositionType={overlayPositionType} - /> -
-
-
-
- - -
-
-
- ); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useEditAlert.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useEditAlert.ts deleted file mode 100644 index 35eb0a893c2..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useEditAlert.ts +++ /dev/null @@ -1,357 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { useCallback, useState } from "react"; - -import { isEqual } from "lodash-es"; -import { useIntl } from "react-intl"; - -import { - type DateAttributeGranularity, - type IAlertAnomalyDetectionGranularity, - type IAlertAnomalyDetectionSensitivity, - type IAlertComparisonOperator, - type IAlertRelativeArithmeticOperator, - type IAlertRelativeOperator, - type IAutomationMetadataObject, - type IAutomationMetadataObjectDefinition, - type IAutomationRecipient, - type ICatalogAttribute, - type ICatalogDateDataset, - type INotificationChannelIdentifier, - type INotificationChannelMetadataObject, - type ISeparators, - isAutomationExternalUserRecipient, - isAutomationUnknownUserRecipient, - isAutomationUserRecipient, -} from "@gooddata/sdk-model"; - -import { useDashboardSelector } from "../../../../../../model/react/DashboardStoreProvider.js"; -import { - selectEnableAnomalyDetectionAlert, - selectTimezone, - selectWeekStart, -} from "../../../../../../model/store/config/configSelectors.js"; -import { selectEntitlementMinimumRecurrenceMinutes } from "../../../../../../model/store/entitlements/entitlementsSelectors.js"; -import { selectEffectiveDashboardTimezone } from "../../../../../../model/store/meta/metaSelectors.js"; -import { selectCanUseAiAssistant } from "../../../../../../model/store/permissions/permissionsSelectors.js"; -import { selectCurrentUser } from "../../../../../../model/store/user/userSelectors.js"; -import { - type IMeasureFormatMap, - getDescription, -} from "../../../../../automations/alerting/DefaultAlertingDialog/utils/getters.js"; -import { - isAlertRecipientsValid, - isAlertValueDefined, -} from "../../../../../automations/alerting/DefaultAlertingDialog/utils/guards.js"; -import { - transformAlertByAnomalyDetection, - transformAlertByAttribute, - transformAlertByComparisonOperator, - transformAlertByDestination, - transformAlertByGranularity, - transformAlertByMetric, - transformAlertByRelativeOperator, - transformAlertBySensitivity, - transformAlertByTitle, - transformAlertByValue, -} from "../../../../../automations/alerting/DefaultAlertingDialog/utils/transformation.js"; -import { - type AlertAttribute, - type AlertMetric, - type AlertMetricComparatorType, -} from "../../../../../automations/alerting/types.js"; -import { isEmail } from "../../../../../automations/scheduledEmail/utils/validate.js"; -import { convertUserToAutomationRecipient } from "../../../../../automations/shared/utils/automationUtils.js"; - -const DEFAULT_MIN_RECURRENCE_MINUTES = "60"; - -export interface IUseEditAlertProps { - metrics: AlertMetric[]; - attributes: AlertAttribute[]; - alert: IAutomationMetadataObject; - measureFormatMap: IMeasureFormatMap; - catalogAttributes: ICatalogAttribute[]; - catalogDateDatasets: ICatalogDateDataset[]; - destinations: INotificationChannelIdentifier[] | INotificationChannelMetadataObject[]; - separators?: ISeparators; - onCreate?: (alert: IAutomationMetadataObjectDefinition) => void; - onUpdate?: (alert: IAutomationMetadataObject) => void; -} - -export const useEditAlert = ({ - metrics, - attributes, - alert, - onCreate, - onUpdate, - measureFormatMap, - destinations, - separators, -}: IUseEditAlertProps) => { - const [viewMode, setViewMode] = useState<"edit" | "configuration">("edit"); - const [updatedAlert, setUpdatedAlert] = useState(alert); - const [warningMessage, setWarningMessage] = useState(undefined); - const currentUser = useDashboardSelector(selectCurrentUser); - const enableAnomalyDetectionAlert = useDashboardSelector(selectEnableAnomalyDetectionAlert); - const enableAiAssistant = useDashboardSelector(selectCanUseAiAssistant); - const weekStart = useDashboardSelector(selectWeekStart); - // the custom dashboard timezone (view-mode override or dashboard configuration) wins over - // the workspace setting for the alert comparison-window computation - const workspaceTimezone = useDashboardSelector(selectTimezone); - const customTimezone = useDashboardSelector(selectEffectiveDashboardTimezone); - const timezone = customTimezone ?? workspaceTimezone; - const intl = useIntl(); - - const minimumRecurrenceMinutesEntitlement = useDashboardSelector( - selectEntitlementMinimumRecurrenceMinutes, - ); - const allowHourlyRecurrence = - parseInt(minimumRecurrenceMinutesEntitlement?.value ?? DEFAULT_MIN_RECURRENCE_MINUTES, 10) === 60; - - const selectedDestination = destinations.find( - (destination) => destination.id === updatedAlert.notificationChannel, - ); - const defaultUser = convertUserToAutomationRecipient(currentUser); - const allowExternalRecipients = selectedDestination?.allowedRecipients === "external"; - const allowOnlyLoggedUserRecipients = selectedDestination?.allowedRecipients === "creator"; - - const changeMeasure = useCallback( - (measure: AlertMetric) => { - setUpdatedAlert((alert) => - transformAlertByMetric(metrics, alert, measure, measureFormatMap, weekStart, timezone), - ); - }, - [measureFormatMap, metrics, weekStart, timezone], - ); - - const changeAttribute = useCallback( - ( - attribute: AlertAttribute | undefined, - value: - | { - title: string; - value: string; - name: string; - } - | undefined, - ) => { - setUpdatedAlert((alert) => transformAlertByAttribute(attributes, alert, attribute, value)); - }, - [attributes], - ); - - const changeComparisonOperator = useCallback( - (measure: AlertMetric, comparisonOperator: IAlertComparisonOperator) => { - setUpdatedAlert((alert) => - transformAlertByComparisonOperator(metrics, alert, measure, comparisonOperator), - ); - }, - [metrics], - ); - - const changeAnomalyDetection = useCallback( - (measure: AlertMetric) => { - setUpdatedAlert((alert) => - transformAlertByAnomalyDetection(metrics, alert, measure, weekStart, timezone), - ); - }, - [metrics, weekStart, timezone], - ); - - const changeRelativeOperator = useCallback( - ( - measure: AlertMetric, - relativeOperator: IAlertRelativeOperator, - arithmeticOperator: IAlertRelativeArithmeticOperator, - ) => { - setUpdatedAlert((alert) => - transformAlertByRelativeOperator( - metrics, - alert, - measure, - relativeOperator, - arithmeticOperator, - measureFormatMap, - ), - ); - }, - [measureFormatMap, metrics], - ); - - const changeValue = useCallback((value: number) => { - setUpdatedAlert((alert) => transformAlertByValue(alert, value)); - }, []); - - const changeTitle = useCallback((value: string | undefined) => { - setUpdatedAlert((alert) => transformAlertByTitle(alert, value)); - }, []); - - const changeSensitivity = useCallback((value: IAlertAnomalyDetectionSensitivity) => { - setUpdatedAlert((alert) => transformAlertBySensitivity(alert, value)); - }, []); - - const changeGranularity = useCallback( - (measure: AlertMetric | undefined, value: IAlertAnomalyDetectionGranularity) => { - if (!measure) { - return; - } - setUpdatedAlert((alert) => - transformAlertByGranularity(metrics, alert, measure, value, weekStart), - ); - }, - [metrics, weekStart], - ); - - const changeDestination = useCallback( - (destinationId: string) => { - const previousDestination = destinations.find( - (channel) => alert.notificationChannel === channel.id, - ); - const selectedDestination = destinations.find((channel) => destinationId === channel.id); - - /** - * When allowed recipients are changed from "ALL" to "CREATOR", show warning message - */ - const showWarningMessage = - selectedDestination?.allowedRecipients === "creator" && - previousDestination?.allowedRecipients !== "creator"; - setWarningMessage( - showWarningMessage - ? intl.formatMessage({ id: "insightAlert.config.warning.destination" }) - : undefined, - ); - - /** - * Reset recipients when new notification channel only allows the author/creator - */ - const updatedRecipients = - selectedDestination?.allowedRecipients === "creator" - ? [convertUserToAutomationRecipient(currentUser)] - : undefined; - - setUpdatedAlert((alert) => transformAlertByDestination(alert, destinationId, updatedRecipients)); - }, - [alert.notificationChannel, currentUser, destinations, intl], - ); - - const changeComparisonType = useCallback( - ( - measure: AlertMetric | undefined, - relativeOperator: [IAlertRelativeOperator, IAlertRelativeArithmeticOperator] | undefined, - comparisonType: AlertMetricComparatorType, - granularity?: DateAttributeGranularity, - ) => { - if (!measure || !relativeOperator || !relativeOperator) { - return; - } - const [relativeOperatorValue, arithmeticOperator] = relativeOperator; - setUpdatedAlert((alert) => - transformAlertByRelativeOperator( - metrics, - alert, - measure, - relativeOperatorValue, - arithmeticOperator, - measureFormatMap, - comparisonType, - granularity, - ), - ); - }, - [measureFormatMap, metrics], - ); - - const changeRecipients = useCallback((recipients: IAutomationRecipient[]) => { - setUpdatedAlert((alert) => ({ - ...alert, - recipients, - })); - }, []); - - const configureAlert = useCallback(() => { - setViewMode("configuration"); - }, []); - - const cancelAlertConfiguration = useCallback(() => { - setViewMode("edit"); - }, []); - - const saveAlertConfiguration = useCallback( - (alert: IAutomationMetadataObject) => { - setUpdatedAlert(alert); - cancelAlertConfiguration(); - }, - [cancelAlertConfiguration], - ); - - const createAlert = useCallback(() => { - const title = updatedAlert.title || getDescription(intl, metrics, updatedAlert, separators); - onCreate?.({ - ...updatedAlert, - title, - }); - }, [intl, metrics, onCreate, separators, updatedAlert]); - - const updateAlert = useCallback(() => { - const title = updatedAlert.title || getDescription(intl, metrics, updatedAlert, separators); - onUpdate?.({ - ...updatedAlert, - title, - } as IAutomationMetadataObject); - }, [intl, metrics, onUpdate, separators, updatedAlert]); - - const isValueDefined = isAlertValueDefined(updatedAlert.alert); - const isRecipientsValid = isAlertRecipientsValid(updatedAlert); - const isExternalRecipientsValid = allowExternalRecipients - ? true - : !updatedAlert.recipients?.some(isAutomationExternalUserRecipient); - const hasNoUnknownRecipients = !updatedAlert.recipients?.some(isAutomationUnknownUserRecipient); - const isAlertChanged = !isEqual(updatedAlert, alert); - - const areEmailsValid = - selectedDestination?.destinationType === "smtp" - ? updatedAlert.recipients?.every((v) => - isAutomationUserRecipient(v) ? isEmail(v.email ?? "") : true, - ) - : true; - - const canSubmit = - isValueDefined && - isAlertChanged && - isRecipientsValid && - areEmailsValid && - isExternalRecipientsValid && - hasNoUnknownRecipients; - - return { - defaultUser, - viewMode, - updatedAlert, - canSubmit, - allowOnlyLoggedUserRecipients, - allowExternalRecipients, - warningMessage, - allowHourlyRecurrence, - enableAnomalyDetectionAlert: enableAnomalyDetectionAlert && enableAiAssistant, - // - changeComparisonOperator, - changeAnomalyDetection, - changeRelativeOperator, - changeMeasure, - changeAttribute, - changeValue, - changeTitle, - changeDestination, - changeComparisonType, - changeRecipients, - changeSensitivity, - changeGranularity, - // - configureAlert, - saveAlertConfiguration, - cancelAlertConfiguration, - // - createAlert, - updateAlert, - }; -}; diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.ts deleted file mode 100644 index 4cc4637e9dc..00000000000 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useWidgetAutomationFilters.ts +++ /dev/null @@ -1,72 +0,0 @@ -// (C) 2026 GoodData Corporation - -import { useMemo } from "react"; - -import { - type IFilter, - type IInsightDefinition, - filterIsEmpty, - filterLocalIdentifier, - isAttributeFilter, - isNoopAllTimeDateFilter, -} from "@gooddata/sdk-model"; - -import { useDashboardSelector } from "../../../../../../model/react/DashboardStoreProvider.js"; -import { useWidgetFilters } from "../../../../../../model/react/useWidgetFilters.js"; -import { selectCrossFilteringItems } from "../../../../../../model/store/drill/drillSelectors.js"; -import { type ICrossFilteringItem } from "../../../../../../model/store/drill/types.js"; -import { type FilterableDashboardWidget } from "../../../../../../model/types/layoutTypes.js"; - -export function useWidgetAutomationFilters(widget?: FilterableDashboardWidget, insight?: IInsightDefinition) { - const widgetFiltersQuery = useWidgetFilters(widget, insight); - const crossFilteringItems = useDashboardSelector(selectCrossFilteringItems); - - return useMemo(() => { - const { result: widgetFilters, status: widgetFiltersStatus } = widgetFiltersQuery; - const sanitizedWidgetFilters = widgetFilters - ? sanitizeWidgetFilters(widgetFilters, crossFilteringItems) - : undefined; - - if (widgetFiltersStatus === "success" && sanitizedWidgetFilters) { - return { - ...widgetFiltersQuery, - result: sanitizedWidgetFilters, - }; - } - - return widgetFiltersQuery; - }, [crossFilteringItems, widgetFiltersQuery]); -} - -function sanitizeWidgetFilters(filters: IFilter[], crossFilteringItems: ICrossFilteringItem[]): IFilter[] { - const withoutCrossFiltering = removeCrossFilteringFilters(filters, crossFilteringItems); - const withoutAllTimeDateFilters = removeAllTimeDateFilters(withoutCrossFiltering); - return removeEmptyAttributeFilters(withoutAllTimeDateFilters); -} - -function removeCrossFilteringFilters( - filters: IFilter[], - crossFilteringItems: ICrossFilteringItem[], -): IFilter[] { - const crossFilteringFilterLocalIdentifiers = new Set( - crossFilteringItems.flatMap((c) => c.filterLocalIdentifiers), - ); - return filters.filter((filter) => { - const filterLocalId = filterLocalIdentifier(filter); - return filterLocalId ? !crossFilteringFilterLocalIdentifiers.has(filterLocalId) : true; - }); -} - -function removeEmptyAttributeFilters(filters: IFilter[]): IFilter[] { - return filters.filter((filter) => { - if (isAttributeFilter(filter)) { - return !filterIsEmpty(filter); - } - - return true; - }); -} - -function removeAllTimeDateFilters(filters: IFilter[]): IFilter[] { - return filters.filter((filter) => !isNoopAllTimeDateFilter(filter)); -} diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.fixture.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.fixture.ts rename to libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.ts b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.ts index eefef70522b..839207aefb4 100644 --- a/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.ts +++ b/libs/sdk-ui-dashboard/src/presentation/widget/insight/configuration/InsightDrillConfigPanel/drillConfigMapper.test.ts @@ -6,8 +6,8 @@ import { describe, expect, it } from "vitest"; import { type IInsightWidget, idRef } from "@gooddata/sdk-model"; -import { availableDrillTargets, globalDrillDowns } from "./drillConfigMapper.fixture.js"; import { getGlobalDrillDownMappedConfigForWidget } from "./drillConfigMapper.js"; +import { availableDrillTargets, globalDrillDowns } from "./drillConfigMapper.test.helpers.js"; describe("drillConfigMapper", () => { describe("getGlobalDrillDownMappedConfigForWidget", () => { diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/Dashboard.fixtures.ts b/libs/sdk-ui-dashboard/src/tests/Dashboard.test.helpers.ts similarity index 100% rename from libs/sdk-ui-dashboard/src/model/fixtures/Dashboard.fixtures.ts rename to libs/sdk-ui-dashboard/src/tests/Dashboard.test.helpers.ts diff --git a/libs/sdk-ui-dashboard/src/model/fixtures/SimpleDashboard.fixtures.ts b/libs/sdk-ui-dashboard/src/tests/SimpleDashboard.test.helpers.ts similarity index 98% rename from libs/sdk-ui-dashboard/src/model/fixtures/SimpleDashboard.fixtures.ts rename to libs/sdk-ui-dashboard/src/tests/SimpleDashboard.test.helpers.ts index bc90335c4f7..55de5697663 100644 --- a/libs/sdk-ui-dashboard/src/model/fixtures/SimpleDashboard.fixtures.ts +++ b/libs/sdk-ui-dashboard/src/tests/SimpleDashboard.test.helpers.ts @@ -15,9 +15,8 @@ import { } from "@gooddata/sdk-model"; import { type IAvailableDrillTargets } from "@gooddata/sdk-ui"; -import { type IInaccessibleDashboard } from "../types/inaccessibleDashboardTypes.js"; - -import { ComplexDashboardIdentifier } from "./ComplexDashboard.fixtures.js"; +import { ComplexDashboardIdentifier } from "../model/tests/ComplexDashboard.test.helpers.js"; +import { type IInaccessibleDashboard } from "../model/types/inaccessibleDashboardTypes.js"; export const SimpleDashboardIdentifier = "adb4fefa-c5ad-410e-bb2c-d6933e0ec7a0"; export const SimpleDashboardWithReferences = ReferenceRecordings.Recordings.metadata?.dashboards?.[ diff --git a/libs/sdk-ui-dashboard/tsconfig.build.json b/libs/sdk-ui-dashboard/tsconfig.build.json index 957cd0b4b7a..0c69d69ef5f 100644 --- a/libs/sdk-ui-dashboard/tsconfig.build.json +++ b/libs/sdk-ui-dashboard/tsconfig.build.json @@ -1,6 +1,14 @@ { "extends": "../tsconfig.react.json", - "exclude": ["**/test", "**/tests", "**/*.test.ts", "**/*.test.tsx", "**/*.fixture.ts"], + "exclude": [ + "**/test", + "**/tests", + "**/*.test.ts", + "**/*.test.tsx", + "**/*.test.helpers.ts", + "**/*.test.helpers.tsx", + "**/*.fixture.ts" + ], "include": ["src/**/*"], "compilerOptions": { "noCheck": true, diff --git a/libs/sdk-ui-ext/package.json b/libs/sdk-ui-ext/package.json index fbe848951a6..b9816e9566b 100644 --- a/libs/sdk-ui-ext/package.json +++ b/libs/sdk-ui-ext/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-ext", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData.UI SDK - Extensions", "license": "LicenseRef-LICENSE", "author": "GoodData Corporation", @@ -84,7 +84,7 @@ "@gooddata/util": "workspace:*", "@lezer/highlight": "~1.2.3", "classnames": "2.5.1", - "cron-parser": "^5.1.1", + "cron-parser": "5.9.0", "date-fns": "4.1.0", "debounce-promise": "^3.1.2", "default-import": "1.1.5", diff --git a/libs/sdk-ui-ext/src/dataLoaders/InsightDataLoader.test.ts b/libs/sdk-ui-ext/src/dataLoaders/InsightDataLoader.test.ts index 92905103944..417cd6c2b7f 100644 --- a/libs/sdk-ui-ext/src/dataLoaders/InsightDataLoader.test.ts +++ b/libs/sdk-ui-ext/src/dataLoaders/InsightDataLoader.test.ts @@ -6,7 +6,7 @@ import { dummyBackendEmptyData } from "@gooddata/sdk-backend-mockingbird"; import { type IAnalyticalBackend } from "@gooddata/sdk-backend-spi"; import { type IInsight, type ObjRef, idRef } from "@gooddata/sdk-model"; -import { noopWorkspaceInsightsService } from "./dataLoaders.mock.js"; +import { noopWorkspaceInsightsService } from "./dataLoaders.test.helpers.js"; import { clearInsightViewCacheForInsight } from "./index.js"; import { insightDataLoaderFactory } from "./InsightDataLoader.js"; diff --git a/libs/sdk-ui-ext/src/dataLoaders/dataLoaders.mock.ts b/libs/sdk-ui-ext/src/dataLoaders/dataLoaders.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/dataLoaders/dataLoaders.mock.ts rename to libs/sdk-ui-ext/src/dataLoaders/dataLoaders.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/BaseVisualization.test.tsx b/libs/sdk-ui-ext/src/internal/components/BaseVisualization.test.tsx index 9cf95e99ba5..9e1d7897492 100644 --- a/libs/sdk-ui-ext/src/internal/components/BaseVisualization.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/BaseVisualization.test.tsx @@ -22,14 +22,14 @@ import { type IVisualizationMeta, type PluggableVisualizationFactory, } from "../interfaces/VisualizationDescriptor.js"; -import { emptyReferencePoint, justViewByReferencePoint } from "../mocks/referencePointMocks.js"; +import { emptyReferencePoint, justViewByReferencePoint } from "../tests/referencePointMocks.test.helpers.js"; import { dummyColumnVisualizationClass, dummyInsight, dummyTableVisualizationClass, dummyUnknownTypeVisualizationClass, emptyInsight, -} from "../mocks/testMocks.js"; +} from "../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../utils/translations.js"; import { @@ -39,7 +39,7 @@ import { } from "./BaseVisualization.js"; import { AbstractPluggableVisualization } from "./pluggableVisualizations/AbstractPluggableVisualization.js"; import { BaseChartDescriptor } from "./pluggableVisualizations/baseChart/BaseChartDescriptor.js"; -import { DummyVisConstruct } from "./pluggableVisualizations/visConstruct.fixture.js"; +import { DummyVisConstruct } from "./visConstruct.test.helpers.js"; import { CatalogViaTypeToClassMap, type IVisualizationCatalog } from "./VisualizationCatalog.js"; const pluggableVisualizationGetExecutionMock = vi.fn(() => ({}) as IPreparedExecution); diff --git a/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.fixture.ts b/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.fixture.ts rename to libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.ts b/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.ts index 2f2a9734235..a8db950f7cc 100644 --- a/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/attributeHierarchies/attributeHierarchyDialog/utils.test.ts @@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest"; -import { attributesData, catalogAttributes, catalogDateDatasets } from "./utils.fixture.js"; import { appendEmptyAttribute, convertToCatalogAttributeData, @@ -10,6 +9,7 @@ import { findCatalogAttributeByRef, searchAttributes, } from "./utils.js"; +import { attributesData, catalogAttributes, catalogDateDatasets } from "./utils.test.helpers.js"; describe("utils", () => { describe("convertToCatalogAttributeData", () => { diff --git a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorDropdown.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorDropdown.test.tsx index 76240f3387a..02799d5b4a3 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorDropdown.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorDropdown.test.tsx @@ -8,9 +8,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { type IColor } from "@gooddata/sdk-model"; -import { colorPalette } from "../../../../mocks/testColorHelper.js"; import { InternalIntlWrapper } from "../../../../utils/internalIntlProvider.js"; import { type IColoredItemContentProps } from "../coloredItemsList/ColoredItemContent.js"; +import { colorPalette } from "../tests/testColorHelper.test.helpers.js"; import { ColorDropdown, diff --git a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorPalette.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorPalette.test.tsx index 9d3deab05fc..7c9cb00ba87 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorPalette.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/colorDropdown/ColorPalette.test.tsx @@ -9,7 +9,7 @@ import { colorPalette, colorPaletteWithOneColor, getLargePalette, -} from "../../../../mocks/testColorHelper.js"; +} from "../tests/testColorHelper.test.helpers.js"; import { ColorPalette, type IColorPaletteProps } from "./ColorPalette.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.test.tsx index 395de00cd82..aa9fc98e76d 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.test.tsx @@ -5,11 +5,11 @@ import { userEvent } from "@testing-library/user-event"; import { cloneDeep } from "lodash-es"; import { describe, expect, it } from "vitest"; -import { colorPalette } from "../../../../mocks/testColorHelper.js"; import { InternalIntlWrapper } from "../../../../utils/internalIntlProvider.js"; +import { colorPalette } from "../tests/testColorHelper.test.helpers.js"; import { ColoredItemsList, type IColoredItemsListProps } from "./ColoredItemsList.js"; -import { inputItemsMock } from "./mock.js"; +import { inputItemsMock } from "./coloredItemsList.test.helpers.js"; const defaultProps: IColoredItemsListProps = { colorPalette, diff --git a/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/mock.ts b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/coloredItemsList.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/mock.ts rename to libs/sdk-ui-ext/src/internal/components/configurationControls/colors/coloredItemsList/coloredItemsList.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/mocks/testColorHelper.tsx b/libs/sdk-ui-ext/src/internal/components/configurationControls/colors/tests/testColorHelper.test.helpers.tsx similarity index 100% rename from libs/sdk-ui-ext/src/internal/mocks/testColorHelper.tsx rename to libs/sdk-ui-ext/src/internal/components/configurationControls/colors/tests/testColorHelper.test.helpers.tsx diff --git a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BaseChartConfigurationPanel.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BaseChartConfigurationPanel.test.tsx index e77d008c9a5..fd24b1d5d73 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BaseChartConfigurationPanel.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BaseChartConfigurationPanel.test.tsx @@ -7,7 +7,7 @@ import { describe, expect, it } from "vitest"; import { type IAttribute, type IInsightDefinition, type IMeasure } from "@gooddata/sdk-model"; import { DefaultLocale, VisualizationTypes } from "@gooddata/sdk-ui"; -import { insightWithSingleAttribute } from "../../mocks/testMocks.js"; +import { insightWithSingleAttribute } from "../../tests/testMocks.test.helpers.js"; import { BaseChartConfigurationPanel } from "./BaseChartConfigurationPanel.js"; import { type IConfigurationPanelContentProps } from "./ConfigurationPanelContent.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BubbleChartConfigurationPanel.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BubbleChartConfigurationPanel.test.tsx index a95205b28af..c2e05b0fb48 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BubbleChartConfigurationPanel.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BubbleChartConfigurationPanel.test.tsx @@ -6,7 +6,7 @@ import { describe, expect, it } from "vitest"; import { type IInsightDefinition, newMeasure } from "@gooddata/sdk-model"; import { DefaultLocale, VisualizationTypes } from "@gooddata/sdk-ui"; -import { insightWithSingleAttribute, insightWithSingleMeasure } from "../../mocks/testMocks.js"; +import { insightWithSingleAttribute, insightWithSingleMeasure } from "../../tests/testMocks.test.helpers.js"; import { BubbleChartConfigurationPanel } from "./BubbleChartConfigurationPanel.js"; import { type IConfigurationPanelContentProps } from "./ConfigurationPanelContent.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BulletChartConfigurationPanel.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BulletChartConfigurationPanel.test.tsx index 5b09dad24db..edcd9296a65 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationPanels/BulletChartConfigurationPanel.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationPanels/BulletChartConfigurationPanel.test.tsx @@ -6,8 +6,8 @@ import { describe, expect, it } from "vitest"; import { type IBucket, type IInsightDefinition } from "@gooddata/sdk-model"; import { DefaultLocale, VisualizationTypes } from "@gooddata/sdk-ui"; -import { emptyInsight } from "../../mocks/testMocks.js"; -import { attributeItemA1, attributeItemA2 } from "../../mocks/visualizationObjectMocks.js"; +import { emptyInsight } from "../../tests/testMocks.test.helpers.js"; +import { attributeItemA1, attributeItemA2 } from "../../tests/visualizationObjectMocks.test.helpers.js"; import { BulletChartConfigurationPanel } from "./BulletChartConfigurationPanel.js"; import { type IConfigurationPanelContentProps } from "./ConfigurationPanelContent.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/configurationPanels/ScatterPlotConfigurationPanel.test.tsx b/libs/sdk-ui-ext/src/internal/components/configurationPanels/ScatterPlotConfigurationPanel.test.tsx index 19e2e1be481..5c740bf6d91 100644 --- a/libs/sdk-ui-ext/src/internal/components/configurationPanels/ScatterPlotConfigurationPanel.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/configurationPanels/ScatterPlotConfigurationPanel.test.tsx @@ -7,7 +7,7 @@ import { describe, expect, it } from "vitest"; import { type IInsightDefinition, newMeasure } from "@gooddata/sdk-model"; import { DefaultLocale, VisualizationTypes } from "@gooddata/sdk-ui"; -import { insightWithSingleAttribute } from "../../mocks/testMocks.js"; +import { insightWithSingleAttribute } from "../../tests/testMocks.test.helpers.js"; import { type IConfigurationPanelContentProps } from "./ConfigurationPanelContent.js"; import { ScatterPlotConfigurationPanel } from "./ScatterPlotConfigurationPanel.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/AbstractPluggableVisualization.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/AbstractPluggableVisualization.test.tsx index 6d3d5c57c36..04a1f0a027b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/AbstractPluggableVisualization.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/AbstractPluggableVisualization.test.tsx @@ -15,10 +15,10 @@ import { derivedMeasureItems, masterMeasureItems, multipleMetricsNoCategoriesReferencePoint, -} from "../../mocks/referencePointMocks.js"; +} from "../../tests/referencePointMocks.test.helpers.js"; +import { DummyVisConstruct } from "../visConstruct.test.helpers.js"; import { AbstractPluggableVisualization } from "./AbstractPluggableVisualization.js"; -import { DummyVisConstruct } from "./visConstruct.fixture.js"; describe("AbstractPluggableVisualization", () => { class DummyPluggableVisualization extends AbstractPluggableVisualization { diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/PluggableColumnBarCharts.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/PluggableColumnBarCharts.test.tsx index 916849b6021..091aa520c6c 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/PluggableColumnBarCharts.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/PluggableColumnBarCharts.test.tsx @@ -44,11 +44,11 @@ import { threeDifferentDatesReferencePoint, twoIdenticalDatesInRows, twoMeasuresOneCategoryWithStackMeasuresToPercent, -} from "../../mocks/referencePointMocks.js"; +} from "../../tests/referencePointMocks.test.helpers.js"; import { insightWithSingleMeasureAndTwoViewBy, insightWithTwoMeasuresAndViewBy, -} from "../../mocks/testMocks.js"; +} from "../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../utils/translations.js"; import { PluggableColumnChart } from "./columnChart/PluggableColumnChart.js"; @@ -60,7 +60,7 @@ import { insightDefinitionWithStackBy, intersection, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; import { createDrillDefinition, createDrillEvent, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/__snapshots__/PluggableColumnBarCharts.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/__snapshots__/PluggableColumnBarCharts.test.tsx.snap index 2a8a707b335..940439fea14 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/__snapshots__/PluggableColumnBarCharts.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/__snapshots__/PluggableColumnBarCharts.test.tsx.snap @@ -87,6 +87,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should cut out measures "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -105,6 +106,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should cut out measures "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -306,6 +308,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should place third attri "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -324,6 +327,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should place third attri "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -455,6 +459,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should return reference "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -473,6 +478,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should return reference "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -690,6 +696,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should reuse all measure "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -709,6 +716,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should reuse all measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -910,6 +918,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should reuse one measure "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -928,6 +937,7 @@ exports[`PluggableColumnBarCharts > optional stacking > should reuse one measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/PluggableAreaChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/PluggableAreaChart.test.tsx index 65771d38f59..4c9957ac50a 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/PluggableAreaChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/PluggableAreaChart.test.tsx @@ -58,13 +58,13 @@ import { twoMetricsAndOneCategoryAndOneStackRefPoint, twoStackedMetricAndOneCategoryRefPoint, twoStackedMetricAndTwoCategoriesRefPoint, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { insightWithSingleMeasure, insightWithSingleMeasureAndTwoViewBy, insightWithSingleMeasureAndViewBy, insightWithTwoMeasuresAndViewBy, -} from "../../../mocks/testMocks.js"; +} from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -79,7 +79,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableAreaChart } from "./PluggableAreaChart.js"; const { Department, Region } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/__snapshots__/PluggableAreaChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/__snapshots__/PluggableAreaChart.test.tsx.snap index bf6c632af06..755a3847d78 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/__snapshots__/PluggableAreaChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/__snapshots__/PluggableAreaChart.test.tsx.snap @@ -356,6 +356,7 @@ exports[`PluggableAreaChart > optional stacking > should return reference point "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -375,6 +376,7 @@ exports[`PluggableAreaChart > optional stacking > should return reference point "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -542,6 +544,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse all measures, onl "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -561,6 +564,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse all measures, onl "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -722,6 +726,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse one measure, only "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -740,6 +745,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse one measure, only "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -907,6 +913,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse one measure, two "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -926,6 +933,7 @@ exports[`PluggableAreaChart > optional stacking > should reuse one measure, two "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1047,6 +1055,7 @@ exports[`PluggableAreaChart > should cut out measures tail when getting nM 0Vb 1 "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1065,6 +1074,7 @@ exports[`PluggableAreaChart > should cut out measures tail when getting nM 0Vb 1 "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1177,6 +1187,7 @@ exports[`PluggableAreaChart > should return reference point when no categories a "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1195,6 +1206,7 @@ exports[`PluggableAreaChart > should return reference point when no categories a "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/areaChart/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/barChart/PluggableBarChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/barChart/PluggableBarChart.test.tsx index 97c6df71ebd..85313776b7d 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/barChart/PluggableBarChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/barChart/PluggableBarChart.test.tsx @@ -24,8 +24,8 @@ import { twoMetricAndTwoCategoriesRefPoint, twoStackedMetricAndOneCategoryRefPoint, twoStackedMetricAndTwoCategoriesRefPoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/PluggableBaseChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/PluggableBaseChart.test.tsx index 0cf146da8fb..1a125004885 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/PluggableBaseChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/PluggableBaseChart.test.tsx @@ -39,7 +39,7 @@ import { samePeriodPreviousYearAndAttributesRefPoint, simpleStackedReferencePoint, wrongBucketsOrderReferencePoint, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { emptyInsight, insightWithSingleAttribute, @@ -47,7 +47,7 @@ import { insightWithSingleMeasureAndStack, insightWithSingleMeasureAndViewBy, insightWithStacking, -} from "../../../mocks/testMocks.js"; +} from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { BaseChartConfigurationPanel } from "../../configurationPanels/BaseChartConfigurationPanel.js"; import { @@ -62,7 +62,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableBaseChart } from "./PluggableBaseChart.js"; const { Region } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/__snapshots__/PluggableBaseChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/__snapshots__/PluggableBaseChart.test.tsx.snap index 6dd351223f8..81cb7c6249d 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/__snapshots__/PluggableBaseChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/__snapshots__/PluggableBaseChart.test.tsx.snap @@ -86,6 +86,7 @@ exports[`PluggableBaseChart > should cut out measures tail when getting nM 0Vb 1 "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -99,6 +100,7 @@ exports[`PluggableBaseChart > should cut out measures tail when getting nM 0Vb 1 "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -220,6 +222,7 @@ exports[`PluggableBaseChart > should handle wrong order of buckets in reference "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -233,6 +236,7 @@ exports[`PluggableBaseChart > should handle wrong order of buckets in reference "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -399,6 +403,7 @@ exports[`PluggableBaseChart > should return ref. point with multiple metrics and "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -413,6 +418,7 @@ exports[`PluggableBaseChart > should return ref. point with multiple metrics and "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -513,6 +519,7 @@ exports[`PluggableBaseChart > should return reference point with base recommenda "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -526,6 +533,7 @@ exports[`PluggableBaseChart > should return reference point with base recommenda "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -684,6 +692,7 @@ exports[`PluggableBaseChart > should return reference point with multiple metric "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -698,6 +707,7 @@ exports[`PluggableBaseChart > should return reference point with multiple metric "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -820,6 +830,7 @@ exports[`PluggableBaseChart > should return reference point with one metric and "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -833,6 +844,7 @@ exports[`PluggableBaseChart > should return reference point with one metric and "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -1008,6 +1020,7 @@ exports[`PluggableBaseChart > should return reference point with one metric and "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -1021,6 +1034,7 @@ exports[`PluggableBaseChart > should return reference point with one metric and "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -1187,6 +1201,7 @@ exports[`PluggableBaseChart > should return reference point with one metric, one "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -1200,6 +1215,7 @@ exports[`PluggableBaseChart > should return reference point with one metric, one "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -1321,6 +1337,7 @@ exports[`PluggableBaseChart > should return reference point without Date in stac "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -1334,6 +1351,7 @@ exports[`PluggableBaseChart > should return reference point without Date in stac "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -1455,6 +1473,7 @@ exports[`PluggableBaseChart > should use second non-date attribute when switchin "stack": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -1468,6 +1487,7 @@ exports[`PluggableBaseChart > should use second non-date attribute when switchin "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/baseChart/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/PluggableBubbleChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/PluggableBubbleChart.test.tsx index c5b916f10e1..8675e06e624 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/PluggableBubbleChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/PluggableBubbleChart.test.tsx @@ -14,8 +14,8 @@ import { multipleMetricsAndCategoriesReferencePoint, multipleMetricsNoCategoriesReferencePoint, secondaryMeasuresAndAttributeReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/__snapshots__/PluggableBubbleChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/__snapshots__/PluggableBubbleChart.test.tsx.snap index c26943c2614..bf0a59866e1 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/__snapshots__/PluggableBubbleChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bubbleChart/__snapshots__/PluggableBubbleChart.test.tsx.snap @@ -158,6 +158,7 @@ exports[`PluggableBubbleChart > should return reference point with secondary met "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -312,6 +313,7 @@ exports[`PluggableBubbleChart > should return reference point with three measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -499,6 +501,7 @@ exports[`PluggableBubbleChart > should return reference point with three measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/PluggableBulletChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/PluggableBulletChart.test.tsx index 55d9da82910..dbf67f1ae76 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/PluggableBulletChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/PluggableBulletChart.test.tsx @@ -39,8 +39,8 @@ import { twoIdenticalDatesInRowsAndColumns, twoMeasuresBucketsTwoViewByReferencePoint, twoMetricsAndOneViewByRefPoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -55,7 +55,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableBulletChart } from "./PluggableBulletChart.js"; const { Department, Region } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/__snapshots__/PluggableBulletChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/__snapshots__/PluggableBulletChart.test.tsx.snap index a99669e73a2..ca8f850d0f6 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/__snapshots__/PluggableBulletChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/__snapshots__/PluggableBulletChart.test.tsx.snap @@ -554,6 +554,7 @@ exports[`PluggableBulletChart > should return reference point with target and co "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -737,6 +738,7 @@ exports[`PluggableBulletChart > should return reference point with three measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -973,6 +975,7 @@ exports[`PluggableBulletChart > should return reference point with three measure "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/bucketHelper.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/bucketHelper.test.ts index 98f3803f29b..19ff007bdec 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/bucketHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/bucketHelper.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { BucketNames } from "@gooddata/sdk-ui"; import { type IBucketItem } from "../../../interfaces/Visualization.js"; -import { derivedMeasureItems, masterMeasureItems } from "../../../mocks/referencePointMocks.js"; +import { derivedMeasureItems, masterMeasureItems } from "../../../tests/referencePointMocks.test.helpers.js"; import { transformBuckets } from "./bucketHelper.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/bulletChart/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/columnChart/PluggableColumnChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/columnChart/PluggableColumnChart.test.tsx index 44e19c787c4..eb8a9ff76ca 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/columnChart/PluggableColumnChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/columnChart/PluggableColumnChart.test.tsx @@ -22,8 +22,8 @@ import { twoMetricAndTwoCategoriesRefPoint, twoStackedMetricAndOneCategoryRefPoint, twoStackedMetricAndTwoCategoriesRefPoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChart.test.tsx index ffceb6346c4..0cb98f0ac16 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChart.test.tsx @@ -40,8 +40,8 @@ import { twoMetricNoViewByRefpoint, twoMetricsAndOneViewByRefPoint, twoPrimaryStackedMetricAndOneViewByReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChartDeprecated.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChartDeprecated.test.tsx index 4913cb7a8bf..e9260ec5fd0 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChartDeprecated.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/comboChart/PluggableComboChartDeprecated.test.tsx @@ -11,8 +11,8 @@ import { firstMeasureArithmeticNoAttributeReferencePoint, masterMeasureItems, overTimeComparisonDateItem, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/PluggableDependencyWheelChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/PluggableDependencyWheelChart.test.tsx index 27544d2bdb9..93e798d8852 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/PluggableDependencyWheelChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/PluggableDependencyWheelChart.test.tsx @@ -13,8 +13,8 @@ import { metricAndAttributeFromAndTo, mixOfMeasuresWithDerivedAndArithmeticFromDerivedHeatMapReferencePoint, multipleMetricsAndCategoriesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/__snapshots__/PluggableDependencyWheelChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/__snapshots__/PluggableDependencyWheelChart.test.tsx.snap index e45eb118aa0..f45a649a4e4 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/__snapshots__/PluggableDependencyWheelChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/dependencyWheelChart/__snapshots__/PluggableDependencyWheelChart.test.tsx.snap @@ -79,6 +79,7 @@ exports[`PluggableDependencyWheelChart > dependency wheel should allow date attr "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -97,6 +98,7 @@ exports[`PluggableDependencyWheelChart > dependency wheel should allow date attr "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -215,6 +217,7 @@ exports[`PluggableDependencyWheelChart > should return reference point with one "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -233,6 +236,7 @@ exports[`PluggableDependencyWheelChart > should return reference point with one "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -403,6 +407,7 @@ exports[`PluggableDependencyWheelChart > should reuse one measure and order attr "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -421,6 +426,7 @@ exports[`PluggableDependencyWheelChart > should reuse one measure and order attr "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/PluggableDonutChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/PluggableDonutChart.test.tsx index 0b2d96b5dec..65d35dbcbc1 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/PluggableDonutChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/PluggableDonutChart.test.tsx @@ -12,8 +12,8 @@ import { multipleMetricsAndCategoriesReferencePoint, multipleMetricsNoCategoriesReferencePoint, oneMetricNoCategoriesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/__snapshots__/PluggableDonutChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/__snapshots__/PluggableDonutChart.test.tsx.snap index 583f29b5fed..e412318b4e7 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/__snapshots__/PluggableDonutChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/donutChart/__snapshots__/PluggableDonutChart.test.tsx.snap @@ -101,6 +101,7 @@ exports[`PluggableDonutChart > should return reference point with multiple metri "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -194,6 +195,7 @@ exports[`PluggableDonutChart > should return reference point with one metric and "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -328,6 +330,7 @@ exports[`PluggableDonutChart > should return reference point with only one metri "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/drillDownUtil.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/drillDownUtil.test.ts index 13d692df7f7..4dce2e620a0 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/drillDownUtil.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/drillDownUtil.test.ts @@ -19,7 +19,7 @@ import { type IDrillDownDefinition } from "../../interfaces/Visualization.js"; import { modifyBucketsAttributesForDrillDown, reverseAndTrimIntersection } from "./drillDownUtil.js"; import { insightDefinitionToInsight } from "./pluggableVisualizations.test.helpers.js"; -import { reverseAndTrimIntersectionMock } from "./reverseAndTrimIntersectionMock.js"; +import { reverseAndTrimIntersectionMock } from "./reverseAndTrimIntersectionMock.test.helpers.js"; const { Account, Department, Region, Status, Won } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/PluggableFunnelChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/PluggableFunnelChart.test.tsx index 6372dedcd42..0f94b60b8d5 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/PluggableFunnelChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/PluggableFunnelChart.test.tsx @@ -10,8 +10,8 @@ import { multipleMetricsAndCategoriesReferencePoint, multipleMetricsNoCategoriesReferencePoint, oneMetricNoCategoriesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { PluggableFunnelChart } from "./PluggableFunnelChart.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/__snapshots__/PluggableFunnelChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/__snapshots__/PluggableFunnelChart.test.tsx.snap index 8c062f5f72c..a2b20c175b3 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/__snapshots__/PluggableFunnelChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/funnelChart/__snapshots__/PluggableFunnelChart.test.tsx.snap @@ -101,6 +101,7 @@ exports[`PluggableFunnelChart > should return reference point with multiple metr "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -194,6 +195,7 @@ exports[`PluggableFunnelChart > should return reference point with one metric an "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -328,6 +330,7 @@ exports[`PluggableFunnelChart > should return reference point with only one metr "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/PluggableGeoPushpinChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/PluggableGeoPushpinChart.test.tsx index f50119e4354..b2447e4834b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/PluggableGeoPushpinChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/PluggableGeoPushpinChart.test.tsx @@ -16,8 +16,8 @@ import { twoMeasuresWithShowInPercentOnSecondaryAxisReferencePoint, viewByWithDateAndGeoAttributeReferencePoint, viewByWithNonGeoAndGeoAttributeReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/__snapshots__/PluggableGeoPushpinChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/__snapshots__/PluggableGeoPushpinChart.test.tsx.snap index 7b9af67f34f..fe50aea2093 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/__snapshots__/PluggableGeoPushpinChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChart/__snapshots__/PluggableGeoPushpinChart.test.tsx.snap @@ -103,6 +103,7 @@ exports[`PluggableGeoPushpinChart > getExtendedReferencePoint > should return a "segment": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChartNext/PluggableGeoPushpinChartNext.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChartNext/PluggableGeoPushpinChartNext.test.tsx index 715a9cf0681..d63e0167d41 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChartNext/PluggableGeoPushpinChartNext.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/geoChartNext/PluggableGeoPushpinChartNext.test.tsx @@ -29,7 +29,7 @@ import { firstMeasureArithmeticNoAttributeReferencePoint, samePeriodPreviousYearRefPoint, twoMeasuresWithShowInPercentOnSecondaryAxisReferencePoint, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { GeoPushpinConfigurationPanel } from "../../configurationPanels/GeoPushpinConfigurationPanel.js"; import { diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/PluggableHeadline.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/PluggableHeadline.test.tsx index 6a0aa57e8da..9ae795c9923 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/PluggableHeadline.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/PluggableHeadline.test.tsx @@ -30,14 +30,14 @@ import { overTimeComparisonDateItem, samePeriodPrevYearFiltersBucket, simpleStackedReferencePoint, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { emptyInsight, insightWithSingleMeasure, insightWithSinglePrimaryAndSecondaryMeasure, insightWithSinglePrimaryAndSecondaryMeasureNoIdentifier, insightWithSingleSecondaryMeasure, -} from "../../../mocks/testMocks.js"; +} from "../../../tests/testMocks.test.helpers.js"; import { getMeasureItems } from "../../../utils/bucketHelper.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/headlineBucketHelper.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/headlineBucketHelper.test.ts index eb2ce5a8176..5c902d9a12b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/headlineBucketHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/headline/headlineBucketHelper.test.ts @@ -13,7 +13,7 @@ import { dateItem, derivedMeasureItems, masterMeasureItems, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { findComplementaryOverTimeComparisonMeasure, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/PluggableHeatmap.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/PluggableHeatmap.test.tsx index 244fc29429a..183fe86bae2 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/PluggableHeatmap.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/PluggableHeatmap.test.tsx @@ -24,8 +24,8 @@ import { oneMetricNoCategoriesReferencePoint, oneMetricOneCategory, oneMetricOneStackReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -40,7 +40,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableHeatmap } from "./PluggableHeatmap.js"; const { Department, Region } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/__snapshots__/PluggableHeatmap.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/__snapshots__/PluggableHeatmap.test.tsx.snap index 90275ba301b..249cdde5fa2 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/__snapshots__/PluggableHeatmap.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/__snapshots__/PluggableHeatmap.test.tsx.snap @@ -219,6 +219,7 @@ exports[`PluggableHeatmap > heatmap should allow date attribute in column bucket "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -233,6 +234,7 @@ exports[`PluggableHeatmap > heatmap should allow date attribute in column bucket "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -399,6 +401,7 @@ exports[`PluggableHeatmap > should return reference point with one metric, categ "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -413,6 +416,7 @@ exports[`PluggableHeatmap > should return reference point with one metric, categ "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/heatMap/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/PluggableLineChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/PluggableLineChart.test.tsx index 100a6e8e6e2..41a3f78f97b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/PluggableLineChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/PluggableLineChart.test.tsx @@ -49,8 +49,8 @@ import { twoSegmentedMetricAndOneTrendByRefPoint, twoSegmentedMetricAndTwoTrendByRefPoint, wrongBucketsOrderInLineReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -64,7 +64,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "../treeMap/getInsightWithDrillDownAppliedMock.js"; +} from "../tests/getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableLineChart } from "./PluggableLineChart.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/__snapshots__/PluggableLineChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/__snapshots__/PluggableLineChart.test.tsx.snap index b9ba2417c0a..eeaf3610296 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/__snapshots__/PluggableLineChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/lineChart/__snapshots__/PluggableLineChart.test.tsx.snap @@ -341,6 +341,7 @@ exports[`PluggableLineChart > should cut out measures tail when getting nM 0Vb 1 "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -359,6 +360,7 @@ exports[`PluggableLineChart > should cut out measures tail when getting nM 0Vb 1 "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -481,6 +483,7 @@ exports[`PluggableLineChart > should handle wrong order of buckets in reference "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -499,6 +502,7 @@ exports[`PluggableLineChart > should handle wrong order of buckets in reference "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -611,6 +615,7 @@ exports[`PluggableLineChart > should return reference point when no categories a "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -629,6 +634,7 @@ exports[`PluggableLineChart > should return reference point when no categories a "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -751,6 +757,7 @@ exports[`PluggableLineChart > should return reference point with Date in categor "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -769,6 +776,7 @@ exports[`PluggableLineChart > should return reference point with Date in categor "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -891,6 +899,7 @@ exports[`PluggableLineChart > should return reference point with one category an "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -909,6 +918,7 @@ exports[`PluggableLineChart > should return reference point with one category an "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1085,6 +1095,7 @@ exports[`PluggableLineChart > should reuse all measures, only one category and n "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1104,6 +1115,7 @@ exports[`PluggableLineChart > should reuse all measures, only one category and n "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1271,6 +1283,7 @@ exports[`PluggableLineChart > should reuse one measure, only one category and on "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1289,6 +1302,7 @@ exports[`PluggableLineChart > should reuse one measure, only one category and on "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/MekkoDescriptor.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/MekkoDescriptor.ts index 4cc835d5f1e..8ecc253cdf7 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/MekkoDescriptor.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/MekkoDescriptor.ts @@ -50,7 +50,7 @@ export class MekkoDescriptor extends BigChartDescriptor { public getMeta(): IVisualizationMeta { return { supportsExport: true, - supportsZooming: false, + supportsZooming: true, }; } } diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/PluggableMekko.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/PluggableMekko.test.tsx index 675178a85a9..7f4b9066f81 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/PluggableMekko.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/PluggableMekko.test.tsx @@ -17,12 +17,12 @@ import { derivedMeasureItems, emptyReferencePoint, masterMeasureItems, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { insightWithSingleMeasure, insightWithSingleMeasureAndViewBy, insightWithSingleMeasureAndViewByAndStack, -} from "../../../mocks/testMocks.js"; +} from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/__snapshots__/PluggableMekko.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/__snapshots__/PluggableMekko.test.tsx.snap index cceb1ca7b70..213437ee3c4 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/__snapshots__/PluggableMekko.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/mekko/__snapshots__/PluggableMekko.test.tsx.snap @@ -117,6 +117,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -130,6 +131,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -262,6 +264,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -275,6 +278,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -397,6 +401,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -410,6 +415,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -561,6 +567,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "stack": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -574,6 +581,7 @@ exports[`PluggableMekko > getExtendedReferencePoint - bucket transforms > should "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/PluggablePieChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/PluggablePieChart.test.tsx index f473c48d3e9..4d6b6e6e01c 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/PluggablePieChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/PluggablePieChart.test.tsx @@ -18,8 +18,8 @@ import { oneMetricNoCategoriesReferencePoint, oneMetricOneStackReferencePoint, simpleStackedWithoutPropertiesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/__snapshots__/PluggablePieChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/__snapshots__/PluggablePieChart.test.tsx.snap index 07bb5f03732..2326b557b9b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/__snapshots__/PluggablePieChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pieChart/__snapshots__/PluggablePieChart.test.tsx.snap @@ -146,6 +146,7 @@ exports[`PluggablePieChart > should return reference point with multiple metrics "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -239,6 +240,7 @@ exports[`PluggablePieChart > should return reference point with one metric and n "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -340,6 +342,7 @@ exports[`PluggablePieChart > should return reference point with one metric and o "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -474,6 +477,7 @@ exports[`PluggablePieChart > should return reference point with only one metric "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.test.tsx index 67e6cd7115a..11497b83fd4 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.test.tsx @@ -40,13 +40,13 @@ import { tableWithMultipleMeasuresRowsAndColumns, tableWithNativeTotal, tableWithRowColTotalAndRankingFilter, -} from "../../../mocks/referencePointMocks.js"; -import { dummyInsight, emptyInsight } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { dummyInsight, emptyInsight } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillEvent, getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; -import { getInsightWithDrillDownApplied } from "./getInsightWithDrillDownAppliedMock.js"; -import { getMockReferencePoint } from "./mockReferencePoint.js"; +import { getInsightWithDrillDownApplied } from "./getInsightWithDrillDownAppliedMock.test.helpers.js"; +import { getMockReferencePoint } from "./mockReferencePoint.test.helpers.js"; import { PluggablePivotTable, createPivotTableConfig, @@ -61,7 +61,7 @@ import { invalidMeasureSortTooManyLocators, validAttributeSort, validMeasureSort, -} from "./sortMocks.js"; +} from "./sortMocks.test.helpers.js"; import { invalidAttributeColumnWidthItem, invalidMeasureColumnWidthItem, @@ -71,7 +71,7 @@ import { transformedWeakMeasureColumnWidth, validAttributeColumnWidthItem, validMeasureColumnWidthItem, -} from "./widthItemsMock.js"; +} from "./widthItemsMock.test.helpers.js"; describe("PluggablePivotTable", () => { const messages = DEFAULT_MESSAGES[DEFAULT_LANGUAGE]; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/__snapshots__/PluggablePivotTable.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/__snapshots__/PluggablePivotTable.test.tsx.snap index 459eb79a345..cb2db9ddfe2 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/__snapshots__/PluggablePivotTable.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/__snapshots__/PluggablePivotTable.test.tsx.snap @@ -6,6 +6,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given an empty refere "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -24,6 +25,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given an empty refere "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -94,6 +96,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given multipleMetrics "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -112,6 +115,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given multipleMetrics "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -182,6 +186,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -200,6 +205,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -335,6 +341,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -353,6 +360,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -815,6 +823,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -833,6 +842,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1286,6 +1296,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1305,6 +1316,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1764,6 +1776,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1782,6 +1795,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > given simpleStackedRe "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1854,6 +1868,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > should return a new r "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1872,6 +1887,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > should return a new r "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1942,6 +1958,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > should return a new r "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -1960,6 +1977,7 @@ exports[`PluggablePivotTable > getExtendedReferencePoint > should return a new r "columns": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/mockReferencePoint.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/mockReferencePoint.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/mockReferencePoint.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/mockReferencePoint.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortItemsHelpers.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortItemsHelpers.test.ts index da62936a355..8818846de7b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortItemsHelpers.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortItemsHelpers.test.ts @@ -10,9 +10,9 @@ import { type IBucketItem, type IExtendedReferencePoint, } from "../../../interfaces/Visualization.js"; -import { simpleStackedReferencePoint } from "../../../mocks/referencePointMocks.js"; +import { simpleStackedReferencePoint } from "../../../tests/referencePointMocks.test.helpers.js"; -import { getMockReferencePoint } from "./mockReferencePoint.js"; +import { getMockReferencePoint } from "./mockReferencePoint.test.helpers.js"; import { adaptReferencePointSortItemsToPivotTable, addDefaultSort, @@ -26,7 +26,7 @@ import { invalidMeasureSortTooManyLocators, validAttributeSort, validMeasureSort, -} from "./sortMocks.js"; +} from "./sortMocks.test.helpers.js"; const createAttributeBucketItem = (localIdentifier: string, attributeName: string): IBucketItem => ({ aggregation: null as unknown as undefined, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortMocks.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortMocks.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortMocks.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/sortMocks.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/totalsHelper.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/totalsHelper.test.ts index ef4c68cb353..ae5370e3abc 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/totalsHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/totalsHelper.test.ts @@ -5,7 +5,11 @@ import { describe, expect, it } from "vitest"; import { type ITotal } from "@gooddata/sdk-model"; import { type IBucketFilter } from "../../../interfaces/Visualization.js"; -import { attributeFilter, measureValueFilter, rankingFilter } from "../../../mocks/referencePointMocks.js"; +import { + attributeFilter, + measureValueFilter, + rankingFilter, +} from "../../../tests/referencePointMocks.test.helpers.js"; import { removeInvalidTotals } from "./totalsHelpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemHelpers.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemHelpers.test.ts index b8b95a717fb..4bd6145045c 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemHelpers.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemHelpers.test.ts @@ -6,7 +6,7 @@ import { uriRef } from "@gooddata/sdk-model"; import { type ColumnWidthItem, type MeasureGroupDimension } from "@gooddata/sdk-ui-pivot"; import { type IBucketFilter, type IBucketItem } from "../../../interfaces/Visualization.js"; -import { simpleStackedReferencePoint } from "../../../mocks/referencePointMocks.js"; +import { simpleStackedReferencePoint } from "../../../tests/referencePointMocks.test.helpers.js"; import { adaptReferencePointWidthItemsToPivotTable } from "./widthItemsHelpers.js"; import { @@ -23,7 +23,7 @@ import { validMixedValuesColumnWidthItem, validSliceMeasureColumnWidthItem, validWeakMeasureColumnWidthItem, -} from "./widthItemsMock.js"; +} from "./widthItemsMock.test.helpers.js"; describe("adaptReferencePointWidthItemsToPivotTable", () => { const sourceReferencePoint = simpleStackedReferencePoint; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemsMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemsMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemsMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/pivotTable/widthItemsMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/PluggableRadarChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/PluggableRadarChart.test.tsx index 3fad943f401..da5c7c05ea7 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/PluggableRadarChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/PluggableRadarChart.test.tsx @@ -32,8 +32,8 @@ import { twoMeasureBucketsReferencePoint, twoMetricAndOneTrendAndOneSegmentByRefPoint, twoMetricAndOneTrendByRefPoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -47,7 +47,7 @@ import { intersection, sourceInsightDef, targetUri, -} from "../treeMap/getInsightWithDrillDownAppliedMock.js"; +} from "../tests/getInsightWithDrillDownAppliedMock.test.helpers.js"; import { PluggableRadarChart } from "./PluggableRadarChart.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/__snapshots__/PluggableRadarChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/__snapshots__/PluggableRadarChart.test.tsx.snap index ded67320bad..a668b0512cf 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/__snapshots__/PluggableRadarChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/radarChart/__snapshots__/PluggableRadarChart.test.tsx.snap @@ -227,6 +227,7 @@ exports[`PluggableRadarChart > should return reference point with Date in trend "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -245,6 +246,7 @@ exports[`PluggableRadarChart > should return reference point with Date in trend "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -365,6 +367,7 @@ exports[`PluggableRadarChart > should return reference point with one trend and "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -383,6 +386,7 @@ exports[`PluggableRadarChart > should return reference point with one trend and "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -548,6 +552,7 @@ exports[`PluggableRadarChart > should reuse all measures, only one category and "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -567,6 +572,7 @@ exports[`PluggableRadarChart > should reuse all measures, only one category and "trend": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/PluggableRepeater.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/PluggableRepeater.test.tsx index b584f8e9e99..1d6a4af553e 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/PluggableRepeater.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/PluggableRepeater.test.tsx @@ -9,8 +9,8 @@ import { attributeAndColumnsReferencePoint, attributesAndColumnsReferencePoint, attributesAndColumnsWithDatesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithOneColumnAndOneAttribute } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithOneColumnAndOneAttribute } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/__snapshots__/PluggableRepeater.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/__snapshots__/PluggableRepeater.test.tsx.snap index f378a153742..506cd1fc495 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/__snapshots__/PluggableRepeater.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/repeater/__snapshots__/PluggableRepeater.test.tsx.snap @@ -61,6 +61,7 @@ exports[`PluggableRepeater > repeater should not allow date attributes or differ "attribute": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -118,6 +119,7 @@ exports[`PluggableRepeater > repeater should not allow date attributes or differ "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -211,6 +213,7 @@ exports[`PluggableRepeater > should return reference point with one attribute, c "attribute": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -268,6 +271,7 @@ exports[`PluggableRepeater > should return reference point with one attribute, c "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -375,6 +379,7 @@ exports[`PluggableRepeater > should reuse one attribute and measures 1`] = ` "attribute": { "accepts": [ "attribute", + "computedAttribute", ], "allowsReordering": false, "allowsSwapping": true, @@ -432,6 +437,7 @@ exports[`PluggableRepeater > should reuse one attribute and measures 1`] = ` "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/reverseAndTrimIntersectionMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/reverseAndTrimIntersectionMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/reverseAndTrimIntersectionMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/reverseAndTrimIntersectionMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/PluggableSankeyChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/PluggableSankeyChart.test.tsx index 0d58f21c144..983120b9316 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/PluggableSankeyChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/PluggableSankeyChart.test.tsx @@ -13,8 +13,8 @@ import { metricAndAttributeFromAndTo, mixOfMeasuresWithDerivedAndArithmeticFromDerivedHeatMapReferencePoint, multipleMetricsAndCategoriesReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/__snapshots__/PluggableSankeyChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/__snapshots__/PluggableSankeyChart.test.tsx.snap index 37d4d3c3880..f5a6f3fe36c 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/__snapshots__/PluggableSankeyChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/sankeyChart/__snapshots__/PluggableSankeyChart.test.tsx.snap @@ -79,6 +79,7 @@ exports[`PluggableSankeyChart > sankey should allow date attribute in attribute "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -97,6 +98,7 @@ exports[`PluggableSankeyChart > sankey should allow date attribute in attribute "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -215,6 +217,7 @@ exports[`PluggableSankeyChart > should return reference point with one metric, a "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -233,6 +236,7 @@ exports[`PluggableSankeyChart > should return reference point with one metric, a "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -403,6 +407,7 @@ exports[`PluggableSankeyChart > should reuse one measure and order attribute typ "attribute_from": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -421,6 +426,7 @@ exports[`PluggableSankeyChart > should reuse one measure and order attribute typ "attribute_to": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/PluggableScatterPlot.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/PluggableScatterPlot.test.tsx index 33d774e697c..270abc12fcf 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/PluggableScatterPlot.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/PluggableScatterPlot.test.tsx @@ -16,8 +16,8 @@ import { overTimeComparisonDateItem, secondaryMeasureReferencePoint, simpleGeoPushpinReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/__snapshots__/PluggableScatterPlot.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/__snapshots__/PluggableScatterPlot.test.tsx.snap index 5d4d40aaebc..47f6ae3577b 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/__snapshots__/PluggableScatterPlot.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/scatterPlot/__snapshots__/PluggableScatterPlot.test.tsx.snap @@ -61,6 +61,7 @@ exports[`PluggableScatterPlot > should return reference point after switching fr "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -128,6 +129,7 @@ exports[`PluggableScatterPlot > should return reference point after switching fr "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -198,6 +200,7 @@ exports[`PluggableScatterPlot > should return reference point with one secondary "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -265,6 +268,7 @@ exports[`PluggableScatterPlot > should return reference point with one secondary "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -344,6 +348,7 @@ exports[`PluggableScatterPlot > should return reference point with primary and s "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -411,6 +416,7 @@ exports[`PluggableScatterPlot > should return reference point with primary and s "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -481,6 +487,7 @@ exports[`PluggableScatterPlot > should return reference point with primary measu "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -548,6 +555,7 @@ exports[`PluggableScatterPlot > should return reference point with primary measu "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -627,6 +635,7 @@ exports[`PluggableScatterPlot > should return reference point with two measures "attribute": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -694,6 +703,7 @@ exports[`PluggableScatterPlot > should return reference point with two measures "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/getInsightWithDrillDownAppliedMock.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/tests/getInsightWithDrillDownAppliedMock.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/getInsightWithDrillDownAppliedMock.ts rename to libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/tests/getInsightWithDrillDownAppliedMock.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/PluggableTreemap.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/PluggableTreemap.test.tsx index d83823a9a12..12ce1444ef5 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/PluggableTreemap.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/PluggableTreemap.test.tsx @@ -30,8 +30,8 @@ import { threeDatesInColumnChart, twoDatesInColumnChart, twoIdenticalDatesInRowsWithSingleMeasure, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { createDrillDefinition, @@ -39,14 +39,14 @@ import { getLastRenderEl, insightDefinitionToInsight, } from "../pluggableVisualizations.test.helpers.js"; - import { expectedInsightDefDepartment, expectedInsightDefRegion, intersection, sourceInsightDef, targetUri, -} from "./getInsightWithDrillDownAppliedMock.js"; +} from "../tests/getInsightWithDrillDownAppliedMock.test.helpers.js"; + import { PluggableTreemap } from "./PluggableTreemap.js"; const { Department, Region } = ReferenceMd; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/__snapshots__/PluggableTreemap.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/__snapshots__/PluggableTreemap.test.tsx.snap index 15c7af8065e..abc8171c4cf 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/__snapshots__/PluggableTreemap.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/treeMap/__snapshots__/PluggableTreemap.test.tsx.snap @@ -138,6 +138,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -156,6 +157,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -281,6 +283,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -299,6 +302,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -468,6 +472,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -486,6 +491,7 @@ exports[`PluggableTreemap > should return ref. point with 1 M, 1 Vb, 1 Sb and on "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -607,6 +613,7 @@ exports[`PluggableTreemap > should return ref. point with n M, 0 Vb, 0 Sb for n "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -625,6 +632,7 @@ exports[`PluggableTreemap > should return ref. point with n M, 0 Vb, 0 Sb for n "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -763,6 +771,7 @@ exports[`PluggableTreemap > should return ref. point with n M, 0 Vb, 1 Sb for n "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -781,6 +790,7 @@ exports[`PluggableTreemap > should return ref. point with n M, 0 Vb, 1 Sb for n "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -879,6 +889,7 @@ exports[`PluggableTreemap > should return reference point with 1 M, 0 Vb, 0 Sb f "segment": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, @@ -897,6 +908,7 @@ exports[`PluggableTreemap > should return reference point with 1 M, 0 Vb, 0 Sb f "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsDuplicateDates": true, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/PluggableWaterfallChart.test.tsx b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/PluggableWaterfallChart.test.tsx index 0c8a68871ec..848418dfc74 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/PluggableWaterfallChart.test.tsx +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/PluggableWaterfallChart.test.tsx @@ -15,8 +15,8 @@ import { onePrimaryMetricAndOneViewByRefPoint, overTimeComparisonDateItem, simpleGeoPushpinReferencePoint, -} from "../../../mocks/referencePointMocks.js"; -import { insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/__snapshots__/PluggableWaterfallChart.test.tsx.snap b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/__snapshots__/PluggableWaterfallChart.test.tsx.snap index cbf259eaafb..b1f17616ef6 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/__snapshots__/PluggableWaterfallChart.test.tsx.snap +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/waterfallChart/__snapshots__/PluggableWaterfallChart.test.tsx.snap @@ -109,6 +109,7 @@ exports[`PluggableWaterfallChart > should return reference point after switching "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -246,6 +247,7 @@ exports[`PluggableWaterfallChart > should return reference point with multi meas "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, @@ -355,6 +357,7 @@ exports[`PluggableWaterfallChart > should return reference point with one measur "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": false, diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/PluggableXirr.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/PluggableXirr.test.ts index 3354179dba8..fe335851f36 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/PluggableXirr.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/PluggableXirr.test.ts @@ -7,8 +7,11 @@ import { type IDrillableItem } from "@gooddata/sdk-ui"; import { CoreXirr, type ICoreChartProps } from "@gooddata/sdk-ui-charts"; import { type IVisConstruct, type IVisProps } from "../../../interfaces/Visualization.js"; -import { emptyReferencePoint, measuresAndDateReferencePoint } from "../../../mocks/referencePointMocks.js"; -import { emptyInsight, insightWithSingleMeasure } from "../../../mocks/testMocks.js"; +import { + emptyReferencePoint, + measuresAndDateReferencePoint, +} from "../../../tests/referencePointMocks.test.helpers.js"; +import { emptyInsight, insightWithSingleMeasure } from "../../../tests/testMocks.test.helpers.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../../../utils/translations.js"; import { getLastRenderEl } from "../pluggableVisualizations.test.helpers.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/xirrBucketHelper.test.ts b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/xirrBucketHelper.test.ts index 2b2f8adb130..22610b66dfb 100644 --- a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/xirrBucketHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/xirr/xirrBucketHelper.test.ts @@ -11,7 +11,7 @@ import { dateItem, derivedMeasureItems, masterMeasureItems, -} from "../../../mocks/referencePointMocks.js"; +} from "../../../tests/referencePointMocks.test.helpers.js"; import { getXirrBuckets } from "./xirrBucketHelper.js"; diff --git a/libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/visConstruct.fixture.ts b/libs/sdk-ui-ext/src/internal/components/visConstruct.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/components/pluggableVisualizations/visConstruct.fixture.ts rename to libs/sdk-ui-ext/src/internal/components/visConstruct.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/constants/bucket.ts b/libs/sdk-ui-ext/src/internal/constants/bucket.ts index bc161fa4624..2181fdae544 100644 --- a/libs/sdk-ui-ext/src/internal/constants/bucket.ts +++ b/libs/sdk-ui-ext/src/internal/constants/bucket.ts @@ -1,4 +1,5 @@ -// (C) 2019-2020 GoodData Corporation +// (C) 2019-2026 GoodData Corporation + // Buckets export const FILTERS = "filters"; @@ -21,4 +22,5 @@ export const METRIC = "metric"; export const FACT = "fact"; export const DATE = "date"; export const ATTRIBUTE = "attribute"; +export const COMPUTED_ATTRIBUTE = "computedAttribute"; export const GEO_ATTRIBUTE = "geo_attribute"; diff --git a/libs/sdk-ui-ext/src/internal/constants/supportedProperties.ts b/libs/sdk-ui-ext/src/internal/constants/supportedProperties.ts index be9c3ac15a1..bb8f98bc391 100644 --- a/libs/sdk-ui-ext/src/internal/constants/supportedProperties.ts +++ b/libs/sdk-ui-ext/src/internal/constants/supportedProperties.ts @@ -302,6 +302,7 @@ export const MEKKO_SUPPORTED_PROPERTIES = [ ...BASE_X_AXIS_PROPERTIES, ...BASE_PRIMARY_AXIS_PROPERTIES, "colorMapping", + "zoomInsight", "disableDrillDown", "disableAlerts", "disableScheduledExports", diff --git a/libs/sdk-ui-ext/src/internal/constants/uiConfig.test.ts b/libs/sdk-ui-ext/src/internal/constants/uiConfig.test.ts new file mode 100644 index 00000000000..32194575584 --- /dev/null +++ b/libs/sdk-ui-ext/src/internal/constants/uiConfig.test.ts @@ -0,0 +1,65 @@ +// (C) 2026 GoodData Corporation + +import { describe, expect, it } from "vitest"; + +import { type IBucketUiConfig } from "../interfaces/Visualization.js"; + +import { ATTRIBUTE, COMPUTED_ATTRIBUTE, GEO_ATTRIBUTE, METRIC } from "./bucket.js"; +import * as uiConfigs from "./uiConfig.js"; + +type BucketEntry = { config: string; bucket: string; accepts: string[] }; + +/** + * Every bucket of every visualization config, flattened, so the assertions below cannot silently + * miss a config that is added later. + */ +function allBuckets(): BucketEntry[] { + return Object.entries(uiConfigs).flatMap(([config, value]) => { + const buckets = (value as { buckets?: Record })?.buckets; + if (!buckets) { + return []; + } + + return Object.entries(buckets) + .filter(([, bucket]) => Array.isArray(bucket?.accepts)) + .map(([bucket, { accepts }]) => ({ config, bucket, accepts: accepts as string[] })); + }); +} + +describe("uiConfig computed attributes", () => { + const buckets = allBuckets(); + + it("should have found the visualization bucket configs", () => { + // a guard on the guard: if the shape of uiConfig.ts changes so that nothing is found, the + // assertions below would pass vacuously + expect(buckets.length).toBeGreaterThan(20); + }); + + it("should accept a computed attribute in every bucket that groups by an attribute", () => { + // A computed attribute is offered wherever an attribute GROUPS the result. It is deliberately + // not offered where a bucket only takes an attribute to coerce it into a measure (those also + // accept METRIC - the backend rejects a computed attribute as a COUNT witness), in the + // filters bucket (filtering by one is not supported yet), and in the geo buckets that need + // geo display forms (those also accept GEO_ATTRIBUTE - a computed attribute has none). + const missing = buckets.filter( + ({ bucket, accepts }) => + accepts.includes(ATTRIBUTE) && + !accepts.includes(COMPUTED_ATTRIBUTE) && + !accepts.includes(METRIC) && + !accepts.includes(GEO_ATTRIBUTE) && + bucket !== "filters", + ); + + expect(missing).toEqual([]); + }); + + it("should never accept a computed attribute in a measure, filter or geo bucket", () => { + const unexpected = buckets.filter( + ({ bucket, accepts }) => + accepts.includes(COMPUTED_ATTRIBUTE) && + (accepts.includes(METRIC) || accepts.includes(GEO_ATTRIBUTE) || bucket === "filters"), + ); + + expect(unexpected).toEqual([]); + }); +}); diff --git a/libs/sdk-ui-ext/src/internal/constants/uiConfig.ts b/libs/sdk-ui-ext/src/internal/constants/uiConfig.ts index 1d2589e5134..f1779998e30 100644 --- a/libs/sdk-ui-ext/src/internal/constants/uiConfig.ts +++ b/libs/sdk-ui-ext/src/internal/constants/uiConfig.ts @@ -4,7 +4,7 @@ import { BucketNames, OverTimeComparisonTypes, VisualizationTypes } from "@goodd import { type IUiConfig } from "../interfaces/Visualization.js"; -import { ATTRIBUTE, DATE, FACT, GEO_ATTRIBUTE, METRIC } from "./bucket.js"; +import { ATTRIBUTE, COMPUTED_ATTRIBUTE, DATE, FACT, GEO_ATTRIBUTE, METRIC } from "./bucket.js"; export const MAX_METRICS_COUNT = 40; export const DEFAULT_PIE_METRICS_COUNT = 1; @@ -42,7 +42,7 @@ export const measuresBase = { }; export const viewBase = { - accepts: [ATTRIBUTE, DATE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE, DATE], itemsLimit: MAX_CATEGORIES_COUNT, itemsLimitByType: { date: 1, @@ -54,7 +54,7 @@ export const viewBase = { }; const stackBase = { - accepts: [ATTRIBUTE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE], itemsLimit: MAX_STACKS_COUNT, allowsSwapping: true, allowsReordering: false, @@ -64,7 +64,7 @@ const stackBase = { const stackBaseWithDate = { ...stackBase, - accepts: [ATTRIBUTE, DATE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE, DATE], }; export const defaultFilters = { @@ -610,7 +610,7 @@ export const DEFAULT_HEATMAP_UICONFIG: IUiConfig = { allowsDuplicateItems: true, }, view: { - accepts: [ATTRIBUTE, DATE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE, DATE], itemsLimit: 1, allowsSwapping: true, allowsReordering: false, @@ -620,7 +620,7 @@ export const DEFAULT_HEATMAP_UICONFIG: IUiConfig = { canAddItems: true, }, stack: { - accepts: [ATTRIBUTE, DATE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE, DATE], itemsLimit: 1, allowsSwapping: true, allowsReordering: false, @@ -793,7 +793,7 @@ const geoMeasuresBase = { const geoAttributesBase = { ...viewBase, - accepts: [ATTRIBUTE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE], canAddItems: true, itemsLimit: DEFAULT_GEO_ATTRIBUTES_COUNT, }; @@ -882,7 +882,7 @@ export const DEFAULT_REPEATER_UI_CONFIG: IUiConfig = { buckets: { attribute: { ...viewBase, - accepts: [ATTRIBUTE], + accepts: [ATTRIBUTE, COMPUTED_ATTRIBUTE], itemsLimit: 1, canAddItems: true, allowsSwapping: true, diff --git a/libs/sdk-ui-ext/src/internal/interfaces/Visualization.test.ts b/libs/sdk-ui-ext/src/internal/interfaces/Visualization.test.ts index 2e37c50f530..0cb075e9bcd 100644 --- a/libs/sdk-ui-ext/src/internal/interfaces/Visualization.test.ts +++ b/libs/sdk-ui-ext/src/internal/interfaces/Visualization.test.ts @@ -2,13 +2,12 @@ import { describe, expect, it } from "vitest"; -import { InvalidInputTestCases } from "../../../testUtils/typeGuards.js"; import { attributeFilter, dateFilter, measureValueFilter, rankingFilter, -} from "../mocks/referencePointMocks.js"; +} from "../tests/referencePointMocks.test.helpers.js"; import { isAttributeFilter, isDateFilter, @@ -16,6 +15,8 @@ import { isRankingFilter, } from "../utils/bucketHelper.js"; +import { InvalidInputTestCases } from "./typeGuards.test.helpers.js"; + describe("Visualization typeguards", () => { describe("isDateFilter", () => { const Scenarios: Array<[boolean, string, any]> = [ diff --git a/libs/sdk-ui-ext/testUtils/typeGuards.ts b/libs/sdk-ui-ext/src/internal/interfaces/typeGuards.test.helpers.ts similarity index 93% rename from libs/sdk-ui-ext/testUtils/typeGuards.ts rename to libs/sdk-ui-ext/src/internal/interfaces/typeGuards.test.helpers.ts index 56ecf80e8da..0d105363b75 100644 --- a/libs/sdk-ui-ext/testUtils/typeGuards.ts +++ b/libs/sdk-ui-ext/src/internal/interfaces/typeGuards.test.helpers.ts @@ -1,4 +1,4 @@ -// (C) 2019 GoodData Corporation +// (C) 2019-2026 GoodData Corporation /** * Specifies test scenarios with various invalid inputs for type guards. These scenarios should be diff --git a/libs/sdk-ui-ext/src/internal/mocks/referencePointMocks.ts b/libs/sdk-ui-ext/src/internal/tests/referencePointMocks.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/mocks/referencePointMocks.ts rename to libs/sdk-ui-ext/src/internal/tests/referencePointMocks.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/mocks/testMocks.ts b/libs/sdk-ui-ext/src/internal/tests/testMocks.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/mocks/testMocks.ts rename to libs/sdk-ui-ext/src/internal/tests/testMocks.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/mocks/visualizationObjectMocks.ts b/libs/sdk-ui-ext/src/internal/tests/visualizationObjectMocks.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/mocks/visualizationObjectMocks.ts rename to libs/sdk-ui-ext/src/internal/tests/visualizationObjectMocks.test.helpers.ts diff --git a/libs/sdk-ui-ext/src/internal/translations/pt-BR.json b/libs/sdk-ui-ext/src/internal/translations/pt-BR.json index beeac76a093..b2475103d29 100644 --- a/libs/sdk-ui-ext/src/internal/translations/pt-BR.json +++ b/libs/sdk-ui-ext/src/internal/translations/pt-BR.json @@ -481,14 +481,14 @@ "automations.filter.status.success": "Êxito", "automations.filter.status.failed": "Falhou", "automations.filter.status.neverRun": "Nunca corra", - "automations.filter.dashboard.label": "Dashboard", + "automations.filter.dashboard.label": "Painel", "automations.filter.recipients.label": "Destinatários", "automations.filter.createdBy.label": "Criado por", "automations.filter.currentUser": "Usuário atual", "automations.cell.lastRun.never": "Nunca", "automations.column.id": "ID", "automations.column.name": "Nome", - "automations.column.dashboard": "Dashboard", + "automations.column.dashboard": "Painel", "automations.column.widget": "Widget", "automations.column.attachments": "Anexos", "automations.column.nextRun": "Próxima execução", diff --git a/libs/sdk-ui-ext/src/internal/translations/pt-PT.json b/libs/sdk-ui-ext/src/internal/translations/pt-PT.json index e2893d8cc33..a1de3c9fb55 100644 --- a/libs/sdk-ui-ext/src/internal/translations/pt-PT.json +++ b/libs/sdk-ui-ext/src/internal/translations/pt-PT.json @@ -481,14 +481,14 @@ "automations.filter.status.success": "Êxito", "automations.filter.status.failed": "Falhou", "automations.filter.status.neverRun": "Nunca corra", - "automations.filter.dashboard.label": "Dashboard", + "automations.filter.dashboard.label": "Painel", "automations.filter.recipients.label": "Destinatários", "automations.filter.createdBy.label": "Criado por", "automations.filter.currentUser": "Usuário atual", "automations.cell.lastRun.never": "Nunca", "automations.column.id": "ID", "automations.column.name": "Nome", - "automations.column.dashboard": "Dashboard", + "automations.column.dashboard": "Painel", "automations.column.widget": "Widget", "automations.column.attachments": "Anexos", "automations.column.nextRun": "Próxima execução", diff --git a/libs/sdk-ui-ext/src/internal/utils/bucketConfig.test.ts b/libs/sdk-ui-ext/src/internal/utils/bucketConfig.test.ts index 0d6fdb02396..75812493b4a 100644 --- a/libs/sdk-ui-ext/src/internal/utils/bucketConfig.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/bucketConfig.test.ts @@ -22,7 +22,7 @@ import { dateItemWithDateDataset, derivedMeasureItems, masterMeasureItems, -} from "../mocks/referencePointMocks.js"; +} from "../tests/referencePointMocks.test.helpers.js"; import { configureOverTimeComparison, configurePercent } from "./bucketConfig.js"; diff --git a/libs/sdk-ui-ext/src/internal/utils/bucketHelper.test.ts b/libs/sdk-ui-ext/src/internal/utils/bucketHelper.test.ts index 5eb31fbac95..0d3526c1678 100644 --- a/libs/sdk-ui-ext/src/internal/utils/bucketHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/bucketHelper.test.ts @@ -40,8 +40,8 @@ import { oneAttributeTwoFiltersReferencePoint, twoMeasureBucketsReferencePoint, wrongBucketsOrderReferencePoint, -} from "../mocks/referencePointMocks.js"; -import { oneMeasureOneStack, oneMeasureOneView } from "../mocks/visualizationObjectMocks.js"; +} from "../tests/referencePointMocks.test.helpers.js"; +import { oneMeasureOneStack, oneMeasureOneView } from "../tests/visualizationObjectMocks.test.helpers.js"; import { type IMeasureBucketItemsLimit, diff --git a/libs/sdk-ui-ext/src/internal/utils/bucketRules.test.ts b/libs/sdk-ui-ext/src/internal/utils/bucketRules.test.ts index 1998d859f13..66bf3d57b5f 100644 --- a/libs/sdk-ui-ext/src/internal/utils/bucketRules.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/bucketRules.test.ts @@ -23,7 +23,7 @@ import { sliceByWeekBucketItem, thresholdMeasure, twoDateFiltersBucket, -} from "../mocks/referencePointMocks.js"; +} from "../tests/referencePointMocks.test.helpers.js"; import { comparisonAndTrendingRecommendationEnabled, diff --git a/libs/sdk-ui-ext/src/internal/utils/propertiesHelper.test.ts b/libs/sdk-ui-ext/src/internal/utils/propertiesHelper.test.ts index 65d3b1a7bd4..2fc834a7ce5 100644 --- a/libs/sdk-ui-ext/src/internal/utils/propertiesHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/propertiesHelper.test.ts @@ -17,11 +17,7 @@ import { oneMetricAndCategoryAndStackReferencePoint, simpleStackedReferencePoint, twoMeasureBucketsReferencePoint, -} from "../mocks/referencePointMocks.js"; -import { - multipleMetricsAndCategoriesBaseUiConfig, - simpleStackedBaseUiConfig, -} from "../mocks/uiConfigMocks.js"; +} from "../tests/referencePointMocks.test.helpers.js"; import { getColumnWidthsFromProperties, @@ -32,6 +28,10 @@ import { isDualAxisOrSomeSecondaryAxisMeasure, removeImmutableOptionalStackingProperties, } from "./propertiesHelper.js"; +import { + multipleMetricsAndCategoriesBaseUiConfig, + simpleStackedBaseUiConfig, +} from "./uiConfigMocks.test.helpers.js"; describe("propertiesHelper", () => { describe("getSupportedPropertiesControls", () => { diff --git a/libs/sdk-ui-ext/src/internal/utils/sort.test.ts b/libs/sdk-ui-ext/src/internal/utils/sort.test.ts index bab546793dc..1d685995cc8 100644 --- a/libs/sdk-ui-ext/src/internal/utils/sort.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/sort.test.ts @@ -19,14 +19,14 @@ import { SORT_DIR_DESC } from "../constants/sort.js"; import { DEFAULT_BASE_CHART_UICONFIG } from "../constants/uiConfig.js"; import { newAvailableSortsGroup } from "../interfaces/SortConfig.js"; import { type IExtendedReferencePoint } from "../interfaces/Visualization.js"; -import { multipleMetricBucketsAndCategoryReferencePoint } from "../mocks/referencePointMocks.js"; +import { multipleMetricBucketsAndCategoryReferencePoint } from "../tests/referencePointMocks.test.helpers.js"; import { insightWithSingleMeasureAndStack, insightWithSingleMeasureAndTwoViewBy, insightWithSingleMeasureAndViewBy, insightWithSingleMeasureAndViewByAndStack, insightWithTwoMeasuresAndTwoViewBy, -} from "../mocks/testMocks.js"; +} from "../tests/testMocks.test.helpers.js"; import { createSorts, diff --git a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/__snapshots__/bulletChartUiConfigHelper.test.ts.snap b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/__snapshots__/bulletChartUiConfigHelper.test.ts.snap index c7020dfa69a..bd0e6112a1a 100644 --- a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/__snapshots__/bulletChartUiConfigHelper.test.ts.snap +++ b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/__snapshots__/bulletChartUiConfigHelper.test.ts.snap @@ -137,6 +137,7 @@ exports[`bulletChartUiConfigHelper > getBulletChartUiConfig > should return bull "view": { "accepts": [ "attribute", + "computedAttribute", "date", ], "allowsReordering": true, diff --git a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/bulletChartUiConfigHelper.test.ts b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/bulletChartUiConfigHelper.test.ts index 5975b08842a..8e385f3a866 100644 --- a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/bulletChartUiConfigHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/bulletChartUiConfigHelper.test.ts @@ -9,7 +9,7 @@ import { bulletChartWithMeasureInPrimaryBucket, bulletChartWithMeasureInSecondaryBucket, threeMeasuresBucketsReferencePoint, -} from "../../mocks/referencePointMocks.js"; +} from "../../tests/referencePointMocks.test.helpers.js"; import { createInternalIntl } from "../internalIntlProvider.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../translations.js"; diff --git a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelper.test.ts b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelper.test.ts index 72981c45e62..31f937396a6 100644 --- a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelper.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { VisualizationTypes } from "@gooddata/sdk-ui"; import { COMBO_CHART_UICONFIG } from "../../constants/uiConfig.js"; -import { twoMeasureBucketsReferencePoint } from "../../mocks/referencePointMocks.js"; +import { twoMeasureBucketsReferencePoint } from "../../tests/referencePointMocks.test.helpers.js"; import { createInternalIntl } from "../internalIntlProvider.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../translations.js"; diff --git a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelperDeprecated.test.ts b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelperDeprecated.test.ts index 019d3e9fd56..cb697a27972 100644 --- a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelperDeprecated.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/comboChartUiConfigHelperDeprecated.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from "vitest"; import { VisualizationTypes } from "@gooddata/sdk-ui"; import { COMBO_CHART_UICONFIG_DEPRECATED } from "../../constants/uiConfig.js"; -import { twoMeasureBucketsReferencePoint } from "../../mocks/referencePointMocks.js"; +import { twoMeasureBucketsReferencePoint } from "../../tests/referencePointMocks.test.helpers.js"; import { createInternalIntl } from "../internalIntlProvider.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../translations.js"; diff --git a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/headlineUiConfigHelper.test.ts b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/headlineUiConfigHelper.test.ts index 140dd1316e0..fcad3400746 100644 --- a/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/headlineUiConfigHelper.test.ts +++ b/libs/sdk-ui-ext/src/internal/utils/uiConfigHelpers/headlineUiConfigHelper.test.ts @@ -15,11 +15,11 @@ import { CalculateAs, DEFAULT_COMPARISON_PALETTE, type IChartConfig } from "@goo import { type HeadlineControlProperties } from "../../interfaces/ControlProperties.js"; import { type IVisualizationProperties } from "../../interfaces/Visualization.js"; +import { createTestProperties, newInsight } from "../../testDataProvider.js"; import { headlineWithMeasureInPrimaryBucket, headlineWithMeasureInSecondaryBucket, -} from "../../mocks/referencePointMocks.js"; -import { createTestProperties, newInsight } from "../../testDataProvider.js"; +} from "../../tests/referencePointMocks.test.helpers.js"; import { createInternalIntl } from "../internalIntlProvider.js"; import { DEFAULT_LANGUAGE, DEFAULT_MESSAGES } from "../translations.js"; diff --git a/libs/sdk-ui-ext/src/internal/mocks/uiConfigMocks.ts b/libs/sdk-ui-ext/src/internal/utils/uiConfigMocks.test.helpers.ts similarity index 100% rename from libs/sdk-ui-ext/src/internal/mocks/uiConfigMocks.ts rename to libs/sdk-ui-ext/src/internal/utils/uiConfigMocks.test.helpers.ts diff --git a/libs/sdk-ui-filters/.dependency-cruiser.js b/libs/sdk-ui-filters/.dependency-cruiser.js index a9e2df8c341..487a46443d0 100644 --- a/libs/sdk-ui-filters/.dependency-cruiser.js +++ b/libs/sdk-ui-filters/.dependency-cruiser.js @@ -12,9 +12,37 @@ import { // eslint-disable-next-line no-restricted-exports export default { forbidden: [ - ...DefaultRules, + // not-to-unresolvable and non-standard-import are replaced below: @rc-component/picker's package.json + // exports wildcarded "./generate/*" and "./locale/*" subpaths (resolving to es/*.js or lib/*.js + // depending on module system) that dependency-cruiser's tsConfig-based resolver doesn't expand, even + // though both Node's runtime resolver and tsgo resolve it correctly - confirmed by direct testing. + ...DefaultRules.filter((rule) => rule.name !== "not-to-unresolvable"), + { + name: "not-to-unresolvable", + severity: "error", + comment: + "This module depends on a module that cannot be found ('resolved to disk'). If it's an npm " + + "module: add it to your package.json. In all other cases you likely already know what to do.", + from: {}, + to: { + couldNotResolve: true, + pathNot: "^@rc-component/picker/(generate|locale)/", + }, + }, ...DefaultSdkRules, - ...PublicLibraryRules, + ...PublicLibraryRules.filter((rule) => rule.name !== "non-standard-import"), + { + name: "non-standard-import", + severity: "error", + comment: + "This module imports file with non-standard file extension." + + "Import static assets to TypeScript files is not allowed.", + from: {}, + to: { + pathNot: ["^.*.(tsx?|jsx?|json)$", "^@rc-component/picker/(generate|locale)/"], + dependencyTypesNot: ["core"], + }, + }, moduleWithDependencies("AttributeFilter", "src/AttributeFilter", ["src/constants/*", "src/shared/*"]), moduleWithDependencies("DateFilter", "src/DateFilter", ["src/constants/*", "src/shared/*"]), isolatedSubmodule("MeasureValueFilter", "src/MeasureValueFilter"), diff --git a/libs/sdk-ui-filters/api/sdk-ui-filters.api.md b/libs/sdk-ui-filters/api/sdk-ui-filters.api.md index 3a01bc4adfe..70a94b0920f 100644 --- a/libs/sdk-ui-filters/api/sdk-ui-filters.api.md +++ b/libs/sdk-ui-filters/api/sdk-ui-filters.api.md @@ -1405,6 +1405,31 @@ export type InvertableSelection = { irrelevantKeys?: T[]; }; +// @alpha +export interface IPeriodRange { + // (undocumented) + from?: DateString; + // (undocumented) + to?: DateString; +} + +// @alpha (undocumented) +export interface IPeriodRangePickerProps { + // (undocumented) + granularity: PeriodRangePickerGranularity; + // (undocumented) + isMobile: boolean; + // (undocumented) + onRangeChange: (newRange: IPeriodRange) => void; + // (undocumented) + range: IPeriodRange; + // (undocumented) + submitForm: () => void; + weekStart?: WeekStart; + // (undocumented) + withoutApply?: boolean; +} + // @beta (undocumented) export interface IRankingFilterDropdownProps { // (undocumented) @@ -1587,6 +1612,7 @@ export interface ITextFilterStateSummaryProps { export interface IUiAbsoluteDateFilterForm extends IAbsoluteDateFilterForm { emptyValueHandling?: EmptyValues; from?: DateString; + granularity?: DateFilterGranularity; to?: DateString; } @@ -1802,6 +1828,12 @@ export type OnSelectionCommittedCallbackPayload = { // @public (undocumented) export type ParentFilterOverAttributeType = ObjRef | ((parentFilter: IAttributeFilter, index: number) => ObjRef); +// @alpha +export function PeriodRangePicker(props: IPeriodRangePickerProps): JSX.Element; + +// @alpha +export type PeriodRangePickerGranularity = Extract; + // @beta (undocumented) export function RankingFilter(input: IRankingFilterProps): JSX.Element; diff --git a/libs/sdk-ui-filters/package.json b/libs/sdk-ui-filters/package.json index 83b77aa3ee2..a9b415f2d69 100644 --- a/libs/sdk-ui-filters/package.json +++ b/libs/sdk-ui-filters/package.json @@ -1,6 +1,6 @@ { "name": "@gooddata/sdk-ui-filters", - "version": "11.54.0-alpha.5", + "version": "11.54.0-alpha.6", "description": "GoodData.UI SDK - Filter Components", "license": "MIT", "author": "GoodData Corporation", @@ -60,6 +60,7 @@ "@gooddata/sdk-ui": "workspace:*", "@gooddata/sdk-ui-kit": "workspace:*", "@gooddata/util": "workspace:*", + "@rc-component/picker": "1.12.0", "@reduxjs/toolkit": "2.9.0", "classnames": "2.5.1", "date-fns": "4.1.0", diff --git a/libs/sdk-ui-filters/src/AttributeFilter/Components/FilterMenu/FilterMenuLabelItem.tsx b/libs/sdk-ui-filters/src/AttributeFilter/Components/FilterMenu/FilterMenuLabelItem.tsx deleted file mode 100644 index 63ac5493b4e..00000000000 --- a/libs/sdk-ui-filters/src/AttributeFilter/Components/FilterMenu/FilterMenuLabelItem.tsx +++ /dev/null @@ -1,53 +0,0 @@ -// (C) 2007-2026 GoodData Corporation - -import { type IAttributeDisplayFormMetadataObject } from "@gooddata/sdk-model"; -import { SingleSelectListItem, UiIcon } from "@gooddata/sdk-ui-kit"; - -/** - * Props for FilterMenuLabelItem component. - * - * @alpha - */ -export interface IFilterMenuLabelItemProps { - /** - * Label metadata for this menu item. - */ - label: IAttributeDisplayFormMetadataObject; - - /** - * Whether this label is currently selected. - */ - isSelected: boolean; - - /** - * Click handler. - */ - onClick: () => void; -} - -/** - * Individual label menu item in the filter menu "Values as" section. - * - * @alpha - */ -export function FilterMenuLabelItem(props: IFilterMenuLabelItemProps) { - const { label, isSelected, onClick } = props; - - return ( - - isSelected ? ( - - - - ) : null - } - /> - ); -} diff --git a/libs/sdk-ui-filters/src/AttributeFilter/hooks/useAttributeFilterHandlerMethods.ts b/libs/sdk-ui-filters/src/AttributeFilter/hooks/useAttributeFilterHandlerMethods.ts deleted file mode 100644 index e35917cdf4f..00000000000 --- a/libs/sdk-ui-filters/src/AttributeFilter/hooks/useAttributeFilterHandlerMethods.ts +++ /dev/null @@ -1,71 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { type IMultiSelectAttributeFilterHandler } from "../../AttributeFilterHandler/types/attributeFilterHandler.js"; - -/** - * @internal - */ -export const useAttributeFilterHandlerMethods = (handler: IMultiSelectAttributeFilterHandler) => { - return { - init: handler.init, - - onInitStart: handler.onInitStart, - onInitSuccess: handler.onInitSuccess, - onInitError: handler.onInitError, - onInitCancel: handler.onInitCancel, - - loadAttribute: handler.loadAttribute, - cancelAttributeLoad: handler.cancelAttributeLoad, - - onLoadAttributeStart: handler.onLoadAttributeStart, - onLoadAttributeSuccess: handler.onLoadAttributeSuccess, - onLoadAttributeError: handler.onLoadAttributeError, - onLoadAttributeCancel: handler.onLoadAttributeCancel, - - loadInitialElementsPage: handler.loadInitialElementsPage, - cancelInitialElementsPageLoad: handler.cancelInitialElementsPageLoad, - - onLoadInitialElementsPageStart: handler.onLoadInitialElementsPageStart, - onLoadInitialElementsPageSuccess: handler.onLoadInitialElementsPageSuccess, - onLoadInitialElementsPageError: handler.onLoadInitialElementsPageError, - onLoadInitialElementsPageCancel: handler.onLoadInitialElementsPageCancel, - - loadNextElementsPage: handler.loadNextElementsPage, - cancelNextElementsPageLoad: handler.cancelNextElementsPageLoad, - - onLoadNextElementsPageStart: handler.onLoadNextElementsPageStart, - onLoadNextElementsPageSuccess: handler.onLoadNextElementsPageSuccess, - onLoadNextElementsPageError: handler.onLoadNextElementsPageError, - onLoadNextElementsPageCancel: handler.onLoadNextElementsPageCancel, - - loadCustomElements: handler.loadCustomElements, - cancelCustomElementsLoad: handler.cancelCustomElementsLoad, - - onLoadCustomElementsStart: handler.onLoadCustomElementsStart, - onLoadCustomElementsSuccess: handler.onLoadCustomElementsSuccess, - onLoadCustomElementsError: handler.onLoadCustomElementsError, - onLoadCustomElementsCancel: handler.onLoadCustomElementsCancel, - - loadIrrelevantElements: handler.loadIrrelevantElements, - cancelIrrelevantElementsLoad: handler.cancelIrrelevantElementsLoad, - - onLoadIrrelevantElementsStart: handler.onLoadIrrelevantElementsStart, - onLoadIrrelevantElementsSuccess: handler.onLoadIrrelevantElementsSuccess, - onLoadIrrelevantElementsError: handler.onLoadIrrelevantElementsError, - onLoadIrrelevantElementsCancel: handler.onLoadIrrelevantElementsCancel, - - setOrder: handler.setOrder, - setSearch: handler.setSearch, - setLimit: handler.setLimit, - setLimitingAttributeFilters: handler.setLimitingAttributeFilters, - setLimitingDateFilters: handler.setLimitingDateFilters, - setLimitingMeasures: handler.setLimitingMeasures, - setLimitingValidationItems: handler.setLimitingValidationItems, - - changeSelection: handler.changeSelection, - clearSelection: handler.clearSelection, - revertSelection: handler.revertSelection, - invertSelection: handler.invertSelection, - commitSelection: handler.commitSelection, - }; -}; diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/fixtures.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/AttributeFilterHandler.test.helpers.ts similarity index 100% rename from libs/sdk-ui-filters/src/AttributeFilterHandler/fixtures.ts rename to libs/sdk-ui-filters/src/AttributeFilterHandler/AttributeFilterHandler.test.helpers.ts diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/hiddenElements.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/hiddenElements.test.ts index 67e93ab285c..480c91f1337 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/hiddenElements.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/hiddenElements.test.ts @@ -8,8 +8,8 @@ import { hiddenElements, newTestAttributeFilterHandlerWithAttributeFilter, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("hiddenElements option should hide element in getAllElements()", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/init.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/init.test.ts index 8b5fabfa33d..1e96d5d6491 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/init.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/init.test.ts @@ -10,8 +10,8 @@ import { newTestAttributeFilterHandler, newTestAttributeFilterHandlerWithAttributeFilter, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { const commonErrorOuptput: Matcher[] = [ diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/initTotalCount.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/initTotalCount.test.ts index b50977053e0..31a84e84213 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/initTotalCount.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/initTotalCount.test.ts @@ -7,8 +7,8 @@ import { describe, expect, it, vi } from "vitest"; import { newTestAttributeFilterHandlerWithAttributeFilter, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("initTotalCount() should trigger onInitStart() callback", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadAttribute.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadAttribute.test.ts index 8c033f6f74d..0ed88304f20 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadAttribute.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadAttribute.test.ts @@ -10,8 +10,8 @@ import { newTestAttributeFilterHandler, newTestAttributeFilterHandlerWithAttributeFilter, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("getAttribute() should return the attribute after successful initialization", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadCustomElements.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadCustomElements.test.ts index e33f5ec0316..156367447fc 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadCustomElements.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadCustomElements.test.ts @@ -11,8 +11,8 @@ import { newTestAttributeFilterHandlerWithAttributeFilter, newTestAttributeFilterHandlerWithElementsLoadFailures, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("loadCustomElements() should trigger onLoadCustomElementsStart() callback", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadInitialElementsPage.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadInitialElementsPage.test.ts index f3c27de63a3..da9a1cca99f 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadInitialElementsPage.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadInitialElementsPage.test.ts @@ -17,8 +17,8 @@ import { newTestAttributeFilterHandlerWithAttributeFilter, newTestAttributeFilterHandlerWithElementsLoadFailures, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("loadInitialElementsPage() should trigger onLoadInitialElementsPageStart() callback", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadNextElementsPage.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadNextElementsPage.test.ts index 983cff9c366..f98287e018c 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/loadNextElementsPage.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/loadNextElementsPage.test.ts @@ -16,8 +16,8 @@ import { newTestAttributeFilterHandlerWithAttributeFilter, newTestAttributeFilterHandlerWithElementsLoadFailures, positiveAttributeFilterDefaultDF, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("loadNextElementsPage() should trigger onLoadNextElementsPageStart() callback", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/resetLoadOptionsOnSearch.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/resetLoadOptionsOnSearch.test.ts index d2f9491f541..099254f9b02 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/resetLoadOptionsOnSearch.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/resetLoadOptionsOnSearch.test.ts @@ -7,8 +7,8 @@ import { describe, expect, it, vi } from "vitest"; import { negativeAttributeFilterDefaultDF, newTestAttributeFilterHandlerWithAttributeFilter, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("scroll and search to reset offset", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/selection.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/selection.test.ts index e268fe38624..5392beda729 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/selection.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/selection.test.ts @@ -4,7 +4,7 @@ import { describe, expect, it, vi } from "vitest"; -import { newTestAttributeFilterHandler } from "./fixtures.js"; +import { newTestAttributeFilterHandler } from "./AttributeFilterHandler.test.helpers.js"; const changedSelection = { isInverted: true, diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/staticElements.test.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/staticElements.test.ts index 1d932e4d5bb..092ba8e72d2 100644 --- a/libs/sdk-ui-filters/src/AttributeFilterHandler/staticElements.test.ts +++ b/libs/sdk-ui-filters/src/AttributeFilterHandler/staticElements.test.ts @@ -13,8 +13,8 @@ import { limitingMeasures, newTestAttributeFilterHandlerWithAttributeFilter, staticElements, -} from "./fixtures.js"; -import { waitForAsync } from "./testUtils.js"; +} from "./AttributeFilterHandler.test.helpers.js"; +import { waitForAsync } from "./waitForAsync.test.utils.js"; describe("AttributeFilterHandler", () => { it("staticElements option should replace loaded elements on init", async () => { diff --git a/libs/sdk-ui-filters/src/AttributeFilterHandler/testUtils.ts b/libs/sdk-ui-filters/src/AttributeFilterHandler/waitForAsync.test.utils.ts similarity index 100% rename from libs/sdk-ui-filters/src/AttributeFilterHandler/testUtils.ts rename to libs/sdk-ui-filters/src/AttributeFilterHandler/waitForAsync.test.utils.ts diff --git a/libs/sdk-ui-filters/src/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterFormSection.tsx b/libs/sdk-ui-filters/src/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterFormSection.tsx deleted file mode 100644 index 4f19f60e958..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterFormSection.tsx +++ /dev/null @@ -1,107 +0,0 @@ -// (C) 2025-2026 GoodData Corporation - -import { useCallback } from "react"; - -import cx from "classnames"; -import { FormattedMessage } from "react-intl"; - -import { type WeekStart, isAbsoluteDateFilterForm } from "@gooddata/sdk-model"; - -import { type DateFilterRoute } from "../DateFilterBody/types.js"; -import { DateFilterFormWrapper } from "../DateFilterFormWrapper/DateFilterFormWrapper.js"; -import { - type DateFilterOption, - type IDateFilterOptionsByType, - type IUiAbsoluteDateFilterForm, -} from "../interfaces/index.js"; -import { ListItem } from "../ListItem/ListItem.js"; - -import { AbsoluteDateFilterForm } from "./AbsoluteDateFilterForm.js"; - -const ITEM_CLASS_MOBILE = "gd-date-filter-item-mobile"; - -interface IAbsoluteDateFilterFormSection { - filterOptions: IDateFilterOptionsByType; - selectedFilterOption: DateFilterOption; - dateFormat: string; - weekStart: WeekStart; - isTimeForAbsoluteRangeEnabled: boolean; - isSecondsForAbsoluteRangeEnabled?: boolean; - isMobile: boolean; - route: DateFilterRoute; - withoutApply?: boolean; - changeRoute: (newRoute?: DateFilterRoute) => void; - onSelectedFilterOptionChange: (option: DateFilterOption) => void; - closeDropdown: () => void; - onApplyClick: () => void; -} - -export function AbsoluteDateFilterFormSection({ - filterOptions, - selectedFilterOption, - dateFormat, - weekStart, - isTimeForAbsoluteRangeEnabled, - isSecondsForAbsoluteRangeEnabled, - isMobile, - route, - withoutApply, - changeRoute, - onSelectedFilterOptionChange, - closeDropdown, - onApplyClick, -}: IAbsoluteDateFilterFormSection) { - const submitForm = useCallback(() => { - onApplyClick(); - closeDropdown(); - }, [closeDropdown, onApplyClick]); - - if (!filterOptions.absoluteForm) { - return null; - } - - const isSelected = filterOptions.absoluteForm.localIdentifier === selectedFilterOption.localIdentifier; - const isOnRoute = route === "absoluteForm"; - - return ( - <> - {!isMobile || !isOnRoute ? ( - { - changeRoute("absoluteForm"); - if (!isAbsoluteDateFilterForm(selectedFilterOption)) { - onSelectedFilterOptionChange(filterOptions.absoluteForm!); - } - }} - className={cx( - "s-absolute-form", - "s-do-not-close-dropdown-on-click", - isMobile && ITEM_CLASS_MOBILE, - )} - > - {filterOptions.absoluteForm.name ? ( - filterOptions.absoluteForm.name - ) : ( - - )} - - ) : null} - {isSelected && (!isMobile || isOnRoute) ? ( - - - - ) : null} - - ); -} diff --git a/libs/sdk-ui-filters/src/DateFilter/AbsoluteForm.tsx b/libs/sdk-ui-filters/src/DateFilter/AbsoluteForm.tsx deleted file mode 100644 index bb51f2fa164..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/AbsoluteForm.tsx +++ /dev/null @@ -1,72 +0,0 @@ -// (C) 2022-2026 GoodData Corporation - -import { fireEvent } from "@testing-library/react"; - -const rangePicker = ".s-date-range-picker"; -const error = ".s-absolute-range-error"; -const startDateInput = ".s-date-range-picker-from .s-date-range-picker-input-field"; -const endDateInput = ".s-date-range-picker-to .s-date-range-picker-input-field"; -const startTimeInput = ".s-date-range-picker-from .s-date-range-picker-input-time .input-text"; -const endTimeInput = ".s-date-range-picker-to .s-date-range-picker-input-time .input-text"; - -export class AbsoluteForm { - public setStartDate = (value: string) => { - const input = document.querySelector(startDateInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.blur(input); - }; - - public submitStartDateWithEnter = (value: string) => { - const input = document.querySelector(startDateInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.keyDown(input, { key: "Enter" }); - }; - - public setEndDate = (value: string) => { - const input = document.querySelector(endDateInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.blur(input); - }; - - public submitEndDateWithEnter = (value: string) => { - const input = document.querySelector(endDateInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.keyDown(input, { key: "Enter" }); - }; - - public setStartTime = (value: string) => { - const input = document.querySelector(startTimeInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.blur(input); - }; - - public setEndTime = (value: string) => { - const input = document.querySelector(endTimeInput)!; - fireEvent.change(input, { target: { value } }); - fireEvent.blur(input); - }; - - public getStartDate = (): string => { - const input = document.querySelector(startDateInput)!; - return input.value; - }; - - public getEndDate = (): string => { - const input = document.querySelector(endDateInput)!; - return input.value; - }; - - public getStartTime = (): string => { - const input = document.querySelector(startTimeInput)!; - return input.value; - }; - - public getEndTime = (): string => { - const input = document.querySelector(endTimeInput)!; - return input.value; - }; - - public isVisible = () => !!document.querySelector(rangePicker); - - public isErrorVisible = () => !!document.querySelector(error); -} diff --git a/libs/sdk-ui-filters/src/DateFilter/DateFilter.test.tsx b/libs/sdk-ui-filters/src/DateFilter/DateFilter.test.tsx deleted file mode 100644 index ac60707fbe0..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/DateFilter.test.tsx +++ /dev/null @@ -1,807 +0,0 @@ -// (C) 2019-2026 GoodData Corporation - -import { act } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; - -import { suppressConsole } from "@gooddata/util"; - -import { AbsoluteForm } from "./AbsoluteForm.js"; -import { DEFAULT_DATE_FORMAT } from "./constants/Platform.js"; -import { verifyDateFormat } from "./DateFilterCore.js"; -import { - clickAbsoluteFilter, - clickAbsoluteFormFilter, - clickAllTime, - clickApplyButton, - clickCancelButton, - clickConfigurationButton, - clickDateFilterButton, - clickExcludeCurrentPeriodCheckBox, - clickRelativeFormFilter, - clickRelativeFormGranularity, - clickStaticFilter, - createDateFilter, - createDateFilterWithState, - dateToAbsoluteInputFormat, - defaultDateFilterOptions, - getAllStaticItemsLabels, - getDateFilterButtonText, - getExcludeCurrentPeriodCheckbox, - getFilterTitle, - getMonthAgo, - getPresetByItem, - getRelativeFormInputFromValue, - getRelativeFormInputToValue, - getSelectedItemText, - getTodayDate, - isApplyButtonDisabled, - isConfigurationButtonVisible, - isDateFilterBodyVisible, - isDateFilterVisible, - isExcludeCurrentPeriodChecked, - isRelativeFormGranularitySelected, - isRelativeFormSelectMenuVisible, - isRelativeFormVisible, - openAbsoluteFormFilter, - openRelativeFormFilter, - queryExcludeCurrentPeriodCheckbox, - setRelativeFormInputs, -} from "./extendedDateFilters.test.helpers.js"; -import type { DateFilterOption, IDateFilterOptionsByType } from "./interfaces/index.js"; - -describe("DateFilter", () => { - it("should render without crash", () => { - createDateFilter(); - }); - - it("should render with custom name", () => { - const expectedLabel = "Custom filter name"; - createDateFilter({ customFilterName: expectedLabel }); - expect(getFilterTitle()).toEqual(expectedLabel); - }); - - it("should render readonly", () => { - createDateFilter({ dateFilterMode: "readonly" }); - clickDateFilterButton(); - expect(isDateFilterBodyVisible()).toBe(false); - expect(isConfigurationButtonVisible()).toBe(false); - }); - - it("should render hidden", () => { - createDateFilter({ dateFilterMode: "hidden" }); - expect(isDateFilterVisible()).toBe(false); - }); - - describe("configuration", () => { - it("should render configuration button", () => { - const MockConfigComponent = vi.fn(); - createDateFilter({ - FilterConfigurationComponent: MockConfigComponent, - }); - clickDateFilterButton(); - expect(isConfigurationButtonVisible()).toBe(true); - clickConfigurationButton(); - expect(MockConfigComponent).toHaveBeenCalled(); - }); - - it("should not render configuration button", () => { - createDateFilter({ - FilterConfigurationComponent: undefined, - }); - clickDateFilterButton(); - expect(isConfigurationButtonVisible()).toBe(false); - }); - }); - - describe("cancel button", () => { - it("should close DateFilter", () => { - const onCancel = vi.fn(); - createDateFilter({ onCancel }); - clickDateFilterButton(); - clickCancelButton(); - - expect(onCancel).toHaveBeenCalledTimes(1); - expect(isDateFilterBodyVisible()).toBe(false); - }); - - it("should not call onApply", () => { - const onApply = vi.fn(); - createDateFilter({ onApply }); - clickDateFilterButton(); - clickStaticFilter("last-7-days"); - clickCancelButton(); - - expect(onApply).toHaveBeenCalledTimes(0); - expect(isDateFilterBodyVisible()).toBe(false); - }); - - it("should reset absolute filter form contents", () => { - createDateFilter(); - openAbsoluteFormFilter(); - - const absoluteForm = new AbsoluteForm(); - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2017-01-01")); - absoluteForm.setEndDate(dateToAbsoluteInputFormat("2018-01-01")); - clickCancelButton(); - - openAbsoluteFormFilter(); - - const today = getTodayDate(); - const monthAgo = getMonthAgo(); - - expect(absoluteForm.getStartDate()).toEqual(dateToAbsoluteInputFormat(monthAgo)); - expect(absoluteForm.getEndDate()).toEqual(dateToAbsoluteInputFormat(today)); - }); - - it("should reset relative filter contents", () => { - createDateFilter(); - openRelativeFormFilter(); - - setRelativeFormInputs("-2", "2"); - - clickCancelButton(); - - openRelativeFormFilter(); - - expect(getRelativeFormInputFromValue()).toEqual(""); - expect(getRelativeFormInputToValue()).toEqual(""); - }); - }); - - describe("reopening", () => { - it("should keep all time selected when reopening", () => { - const onApply = vi.fn(); - createDateFilter({ onApply }); - - clickDateFilterButton(); - clickAllTime(); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("All time"); - - clickDateFilterButton(); - - expect(getSelectedItemText()).toEqual("All time"); - }); - - it("should keep relative preset selected when reopening", () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - clickDateFilterButton(); - clickStaticFilter("last-month"); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("Last month"); - - clickDateFilterButton(); - - expect(getSelectedItemText()).toEqual("Last month"); - }); - - it("should keep absolute form selected and filled when reopening", () => { - const fromInputValue = dateToAbsoluteInputFormat("2017-01-01"); - const toInputValue = dateToAbsoluteInputFormat("2018-01-01"); - - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - openAbsoluteFormFilter(); - - const absoluteForm = new AbsoluteForm(); - absoluteForm.setStartDate(fromInputValue); - absoluteForm.setEndDate(toInputValue); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("01/01/2017 – 01/01/2018"); - - clickDateFilterButton(); - - expect(getSelectedItemText()).toEqual("Static period"); - - clickAbsoluteFormFilter(); - - expect(absoluteForm.getStartDate()).toEqual(fromInputValue); - expect(absoluteForm.getEndDate()).toEqual(toInputValue); - }); - - it("should keep relative form selected and filled when reopening", () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - openRelativeFormFilter(); - clickRelativeFormGranularity("year"); - - setRelativeFormInputs("-2", "2"); - - clickApplyButton(); - expect(onApply).toHaveBeenCalledTimes(1); - - clickDateFilterButton(); - expect(getSelectedItemText()).toEqual("Relative period"); - - clickRelativeFormFilter(); - expect(isRelativeFormGranularitySelected("year")).toBe(true); - expect(getRelativeFormInputFromValue()).toEqual("2 years ago"); - expect(getRelativeFormInputToValue()).toEqual("2 years ahead"); - }); - }); - - describe("submitting the absolute form with Enter", () => { - // the range picker defers the submit by a tick, see DateRangePicker's updateRangeState - const flushDeferredSubmit = () => - act(async () => { - await new Promise((resolve) => { - setTimeout(resolve, 0); - }); - }); - - it("should apply the date just typed into the range picker", async () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - openAbsoluteFormFilter(); - - const absoluteForm = new AbsoluteForm(); - absoluteForm.submitStartDateWithEnter(dateToAbsoluteInputFormat("2010-04-03")); - await flushDeferredSubmit(); - - expect(onApply).toHaveBeenCalledTimes(1); - expect(onApply).toHaveBeenCalledWith( - expect.objectContaining({ type: "absoluteForm", from: "2010-04-03" }), - false, - ); - expect(getDateFilterButtonText()).toEqual(`04/03/2010 – ${getTodayDate()}`); - }); - - it("should keep the applied start date when the end date is submitted after reopening", async () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - const absoluteForm = new AbsoluteForm(); - - openAbsoluteFormFilter(); - absoluteForm.submitStartDateWithEnter(dateToAbsoluteInputFormat("2010-04-03")); - await flushDeferredSubmit(); - - openAbsoluteFormFilter(); - expect(absoluteForm.getStartDate()).toEqual(dateToAbsoluteInputFormat("2010-04-03")); - - absoluteForm.submitEndDateWithEnter(dateToAbsoluteInputFormat("2018-04-03")); - await flushDeferredSubmit(); - - expect(onApply).toHaveBeenLastCalledWith( - expect.objectContaining({ type: "absoluteForm", from: "2010-04-03", to: "2018-04-03" }), - false, - ); - expect(getDateFilterButtonText()).toEqual("04/03/2010 – 04/03/2018"); - }); - }); - - describe("exclude option", () => { - it("should be disabled when 'All time' selected", () => { - createDateFilter(); - clickDateFilterButton(); - expect(getExcludeCurrentPeriodCheckbox()).toBeDisabled(); - }); - - it("should be enabled when last 12 months", () => { - createDateFilter(); - clickDateFilterButton(); - clickStaticFilter("last-12-months"); - expect(getExcludeCurrentPeriodCheckbox()).not.toBeDisabled(); - }); - - it("should not render when hideDisabledExclude=true and 'All time' selected", () => { - createDateFilter({ hideDisabledExclude: true }); - clickDateFilterButton(); - expect(queryExcludeCurrentPeriodCheckbox()).toBeNull(); - }); - - it("should be disabled when last month", () => { - createDateFilter(); - clickDateFilterButton(); - clickStaticFilter("last-month"); - expect(getExcludeCurrentPeriodCheckbox()).toBeDisabled(); - }); - - it("should be disabled when viewing entire year", () => { - createDateFilter(); - clickDateFilterButton(); - clickStaticFilter("this-year"); - expect(getExcludeCurrentPeriodCheckbox()).toBeDisabled(); - }); - - it("should not render for relative date selection", () => { - createDateFilter(); - openRelativeFormFilter(); - expect(getExcludeCurrentPeriodCheckbox()).not.toBeInTheDocument(); - }); - - it("should not render for absolute form", () => { - createDateFilter(); - openAbsoluteFormFilter(); - expect(getExcludeCurrentPeriodCheckbox()).not.toBeInTheDocument(); - }); - - it("should stay checked when switching between options where it is valid", () => { - createDateFilter(); - clickDateFilterButton(); - clickStaticFilter("last-12-months"); - clickExcludeCurrentPeriodCheckBox(); - expect(isExcludeCurrentPeriodChecked()).toBe(true); - clickStaticFilter("last-7-days"); - expect(isExcludeCurrentPeriodChecked()).toBe(true); - }); - - it("should be disabled when switching to option where it is no longer valid", () => { - createDateFilter(); - clickDateFilterButton(); - clickStaticFilter("last-12-months"); - clickExcludeCurrentPeriodCheckBox(); - expect(isExcludeCurrentPeriodChecked()).toBe(true); - clickStaticFilter("last-month"); - expect(getExcludeCurrentPeriodCheckbox()).toBeDisabled(); - expect(isExcludeCurrentPeriodChecked()).toBe(false); - }); - - it("should use adjusted period as a title when exclude is on", () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - clickDateFilterButton(); - clickStaticFilter("last-12-months"); - clickExcludeCurrentPeriodCheckBox(); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("From 12 to 1 month ago"); - }); - - it("should use adjusted period as a title when exclude is on for named custom presets", () => { - const filterOptions: IDateFilterOptionsByType = { - ...defaultDateFilterOptions, - relativePreset: { - ...defaultDateFilterOptions.relativePreset, - "GDC.time.month": [ - ...(defaultDateFilterOptions.relativePreset?.["GDC.time.month"] ?? []), - { - localIdentifier: "CUSTOM_LAST_12_MONTHS", - type: "relativePreset", - granularity: "GDC.time.month", - from: -11, - to: 0, - name: "Custom last 12 months", - visible: true, - }, - ], - }, - }; - - createDateFilterWithState({ filterOptions }); - clickDateFilterButton(); - clickStaticFilter("custom-last-12-months"); - expect(getSelectedItemText()).toEqual("Custom last 12 months"); - clickExcludeCurrentPeriodCheckBox(); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("From 12 to 1 month ago"); - }); - - it("should use original period title when exclude is off", () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - clickDateFilterButton(); - clickStaticFilter("last-12-months"); - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("Last 12 months"); - }); - }); - - describe("relative presets", () => { - it.each<[string, DateFilterOption[]]>([ - ["last-7-days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["last-30-days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["last-90-days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["this-month", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["last-month", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["last-12-months", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["this-quarter", defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!], - ["last-quarter", defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!], - ["last-4-quarters", defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!], - ["this-year", defaultDateFilterOptions.relativePreset!["GDC.time.year"]!], - ["last-year", defaultDateFilterOptions.relativePreset!["GDC.time.year"]!], - ])("should switch to static date filter with %s", (item, relativePreset) => { - const onApply = vi.fn(); - createDateFilter({ onApply }); - - clickDateFilterButton(); - clickStaticFilter(item); - clickApplyButton(); - - const expectedSelectedItem = getPresetByItem(item, relativePreset); - - expect(onApply).toHaveBeenCalledTimes(1); - expect(onApply).toBeCalledWith(expectedSelectedItem, false); - }); - - it.each<[string, string, DateFilterOption[]]>([ - ["last-7-days", "Last 7 days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["last-30-days", "Last 30 days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["last-90-days", "Last 90 days", defaultDateFilterOptions.relativePreset!["GDC.time.date"]!], - ["this-month", "This month", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["last-month", "Last month", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["last-12-months", "Last 12 months", defaultDateFilterOptions.relativePreset!["GDC.time.month"]!], - ["this-quarter", "This quarter", defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!], - ["last-quarter", "Last quarter", defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!], - [ - "last-4-quarters", - "Last 4 quarters", - defaultDateFilterOptions.relativePreset!["GDC.time.quarter"]!, - ], - ["this-year", "This year", defaultDateFilterOptions.relativePreset!["GDC.time.year"]!], - ["last-year", "Last year", defaultDateFilterOptions.relativePreset!["GDC.time.year"]!], - ])("should set correct button label %s", (item, label, relativePreset) => { - const selectedFilterOption = getPresetByItem(item, relativePreset); - createDateFilter({ selectedFilterOption }); - expect(getDateFilterButtonText()).toBe(label); - }); - - it("should sort static filters in ASC order", () => { - const expectedItems = [ - "This year", - "Last year", - "This quarter", - "Last quarter", - "Last 4 quarters", - "This month", - "Last month", - "Last 12 months", - "Last 7 days", - "Last 30 days", - "Last 90 days", - ]; - - createDateFilter(); - clickDateFilterButton(); - const staticItems = getAllStaticItemsLabels(); - expect(staticItems).toEqual(expectedItems); - }); - }); - - describe("absolute presets", () => { - it.each<[string]>([["christmas-2019"], ["year-2018"]])( - "should switch static date filter to %s", - (item) => { - const onApply = vi.fn(); - createDateFilter({ onApply }); - - clickDateFilterButton(); - - clickAbsoluteFilter(item); - clickApplyButton(); - - const expectedSelectedItem = getPresetByItem(item, defaultDateFilterOptions.absolutePreset!); - - expect(onApply).toHaveBeenCalledTimes(1); - expect(onApply).toBeCalledWith(expectedSelectedItem, false); - }, - ); - }); - - describe("absolute form", () => { - it("should open", () => { - createDateFilter(); - - const absoluteForm = new AbsoluteForm(); - expect(absoluteForm.isVisible()).toBe(false); - clickDateFilterButton(); - expect(absoluteForm.isVisible()).toBe(false); - clickAbsoluteFormFilter(); - expect(absoluteForm.isVisible()).toBe(true); - clickCancelButton(); - expect(absoluteForm.isVisible()).toBe(false); - }); - - it("should set correct values into input", () => { - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - - const from = "2019-10-15"; - const to = "2019-10-25"; - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - const absoluteForm = new AbsoluteForm(); - absoluteForm.setStartDate(dateToAbsoluteInputFormat(from)); - absoluteForm.setEndDate(dateToAbsoluteInputFormat(to)); - - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("10/15/2019 – 10/25/2019"); - }); - - it("should set correct values with desired format", () => { - const dateFormat = "yyyy/MM/dd"; - const onApply = vi.fn(); - createDateFilterWithState({ - dateFormat, - onApply, - }); - const absoluteForm = new AbsoluteForm(); - - const from = "2019-10-15"; - const to = "2019-10-25"; - clickDateFilterButton(); - clickAbsoluteFormFilter(); - absoluteForm.setStartDate(dateToAbsoluteInputFormat(from, dateFormat)); - absoluteForm.setEndDate(dateToAbsoluteInputFormat(to, dateFormat)); - - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("2019/10/15 – 2019/10/25"); - }); - - it("should use the default date format MM/dd/yyyy if the input date format is invalid", () => { - const dateFormat = "ffff"; - const verifiedDateFormat = suppressConsole(() => verifyDateFormat(dateFormat), "warn", [ - { - type: "exact", - value: `Unsupported date format ${dateFormat}, the default format MM/dd/yyyy is used instead.`, - }, - ]); - expect(verifiedDateFormat).toEqual(DEFAULT_DATE_FORMAT); - }); - - it("should render Absolute date filter with no errors when it is opened", () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - expect(absoluteForm.isErrorVisible()).toBe(false); - expect(isApplyButtonDisabled()).toBe(false); - }); - - it.each<[string, string]>([ - ["invalid value", "xxx"], - ["unknown format", "2019-10-10"], - ["invalid day", "12/32/2019"], - ["day as zero", "12/0/2019"], - ["long year", "12/01/2019999"], - ])("should show error when %s is entered to fromInput", (_label, value) => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - absoluteForm.setStartDate(value); - expect(absoluteForm.isErrorVisible()).toBe(true); - }); - - it.each<[string, string]>([ - ["invalid value", "xxx"], - ["unknown format", "2019-10-10"], - ["invalid day", "12/32/2019"], - ["day as zero", "12/0/2019"], - ["long year", "12/01/2019999"], - ])("should show error when %s is entered to toInput", (_label, value) => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - absoluteForm.setEndDate(value); - expect(absoluteForm.isErrorVisible()).toBe(true); - }); - - it("should show errors with more complex interaction", () => { - const from = "2019-01-01"; - const to = "2019-12-31"; - - const onApply = vi.fn(); - createDateFilterWithState({ onApply }); - const absoluteForm = new AbsoluteForm(); - - clickDateFilterButton(); - clickAbsoluteFormFilter(); - expect(absoluteForm.isErrorVisible()).toBe(false); - - absoluteForm.setStartDate("xxx"); - expect(absoluteForm.isErrorVisible()).toBe(true); - - absoluteForm.setStartDate(dateToAbsoluteInputFormat(from)); - expect(absoluteForm.isErrorVisible()).toBe(false); - - absoluteForm.setEndDate("10/10/2019"); - expect(absoluteForm.isErrorVisible()).toBe(false); - - absoluteForm.setEndDate("xxx"); - expect(absoluteForm.isErrorVisible()).toBe(true); - - absoluteForm.setEndDate(dateToAbsoluteInputFormat(to)); - expect(absoluteForm.isErrorVisible()).toBe(false); - clickApplyButton(); - expect(getDateFilterButtonText()).toEqual("01/01/2019 – 12/31/2019"); - }); - - it("should set default value from last month to current month", () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - const expectedFrom = dateToAbsoluteInputFormat(getMonthAgo()); - const expectedTo = dateToAbsoluteInputFormat(getTodayDate()); - expect(absoluteForm.getStartDate()).toEqual(expectedFrom); - expect(absoluteForm.getEndDate()).toEqual(expectedTo); - }); - - it("should not have errors with valid input", () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2019-01-01")); - absoluteForm.setEndDate(dateToAbsoluteInputFormat("2019-01-31")); - expect(absoluteForm.isErrorVisible()).toBe(false); - expect(isApplyButtonDisabled()).toBe(false); - }); - - it('should display error message when "Start" is later than "End" value and start is set twice', () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2019-01-01")); - absoluteForm.setEndDate(dateToAbsoluteInputFormat("2019-01-31")); - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2019-05-01")); - - expect(absoluteForm.getStartDate()).toEqual("05/01/2019"); - expect(absoluteForm.getEndDate()).toEqual("01/31/2019"); - expect(absoluteForm.isErrorVisible()).toBe(true); - expect(isApplyButtonDisabled()).toBe(true); - }); - - it('should display error message when "Start" is later than "End" value', () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2019-01-31")); - absoluteForm.setEndDate(dateToAbsoluteInputFormat("2019-01-01")); - - expect(absoluteForm.getStartDate()).toEqual("01/31/2019"); - expect(absoluteForm.getEndDate()).toEqual("01/01/2019"); - expect(absoluteForm.isErrorVisible()).toBe(true); - expect(isApplyButtonDisabled()).toBe(true); - }); - - it('should not have errors when "from" = "to"', () => { - createDateFilter(); - const absoluteForm = new AbsoluteForm(); - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(dateToAbsoluteInputFormat("2019-01-01")); - absoluteForm.setEndDate(dateToAbsoluteInputFormat("2019-01-01")); - - expect(absoluteForm.isErrorVisible()).toBe(false); - expect(isApplyButtonDisabled()).toBe(false); - }); - }); - - describe("relative form", () => { - it("should open", () => { - createDateFilter(); - clickDateFilterButton(); - expect(isRelativeFormVisible()).toBe(false); - clickRelativeFormFilter(); - expect(isRelativeFormVisible()).toBe(true); - clickCancelButton(); - expect(isRelativeFormVisible()).toBe(false); - }); - - it("should have select menu closed by default", () => { - createDateFilter(); - clickDateFilterButton(); - clickRelativeFormFilter(); - expect(isRelativeFormSelectMenuVisible()).toBe(false); - }); - - it("should have default granularity months", () => { - createDateFilter(); - clickDateFilterButton(); - clickRelativeFormFilter(); - expect(isRelativeFormGranularitySelected("month")).toBe(true); - }); - - it("should clear the form when Granularity changed", () => { - createDateFilter(); - clickDateFilterButton(); - clickRelativeFormFilter(); - - clickRelativeFormGranularity("month"); - - setRelativeFormInputs("-2", "2"); - - expect(getRelativeFormInputFromValue()).toEqual("2 months ago"); - - clickRelativeFormGranularity("year"); - - expect(getRelativeFormInputFromValue()).toEqual(""); - }); - }); - - describe("Absolute form with enabled time", () => { - const dateFormat = "yyyy/MM/dd"; - const fromInputValue = dateToAbsoluteInputFormat("2019-10-15", dateFormat); - const toInputValue = dateToAbsoluteInputFormat("2019-10-25", dateFormat); - const isTimeForAbsoluteRangeEnabled = true; - - it("should set correct values with desired format", () => { - const onApply = vi.fn(); - createDateFilterWithState({ - dateFormat, - onApply, - isTimeForAbsoluteRangeEnabled, - }); - const absoluteForm = new AbsoluteForm(); - const fromTime = "10:00"; - const toTime = "14:00"; - - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(fromInputValue); - absoluteForm.setEndDate(toInputValue); - absoluteForm.setStartTime(fromTime); - absoluteForm.setEndTime(toTime); - - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("2019/10/15, 10:00 – 2019/10/25, 14:00"); - - clickDateFilterButton(); - - expect(getSelectedItemText()).toEqual("Static period"); - - clickAbsoluteFormFilter(); - - expect(absoluteForm.getStartDate()).toEqual(fromInputValue); - expect(absoluteForm.getEndDate()).toEqual(toInputValue); - expect(absoluteForm.getStartTime()).toEqual(fromTime); - expect(absoluteForm.getEndTime()).toEqual(toTime); - }); - - it("should get default time values if not configured", () => { - const onApply = vi.fn(); - createDateFilterWithState({ - dateFormat, - onApply, - isTimeForAbsoluteRangeEnabled, - }); - const absoluteForm = new AbsoluteForm(); - - clickDateFilterButton(); - clickAbsoluteFormFilter(); - - absoluteForm.setStartDate(fromInputValue); - absoluteForm.setEndDate(toInputValue); - - clickApplyButton(); - - expect(getDateFilterButtonText()).toEqual("2019/10/15 – 2019/10/25"); - - clickDateFilterButton(); - - expect(getSelectedItemText()).toEqual("Static period"); - - clickAbsoluteFormFilter(); - - expect(absoluteForm.getStartDate()).toEqual(fromInputValue); - expect(absoluteForm.getEndDate()).toEqual(toInputValue); - expect(absoluteForm.getStartTime()).toEqual("00:00"); - expect(absoluteForm.getEndTime()).toEqual("23:59"); - }); - }); -}); diff --git a/libs/sdk-ui-filters/src/DateFilter/DateFilterBody/DateFilterBodyContent.tsx b/libs/sdk-ui-filters/src/DateFilter/DateFilterBody/DateFilterBodyContent.tsx deleted file mode 100644 index 07368662ee4..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/DateFilterBody/DateFilterBodyContent.tsx +++ /dev/null @@ -1,215 +0,0 @@ -// (C) 2025-2026 GoodData Corporation - -import { useState } from "react"; - -import { isEmpty } from "lodash-es"; -import { useIntl } from "react-intl"; - -import { type DateFilterGranularity, type IActiveCalendars, type WeekStart } from "@gooddata/sdk-model"; -import { useIdPrefixed } from "@gooddata/sdk-ui-kit"; - -import { AbsoluteDateFilterFormSection } from "../AbsoluteDateFilterForm/AbsoluteDateFilterFormSection.js"; -import { AllTimeFilterSection } from "../AllTime/AllTimeFilterSection.js"; -import { - type DateFilterOption, - type IDateFilterOptionsByType, - type IExtendedDateFilterErrors, - type IUiAbsoluteDateFilterForm, - type IUiRelativeDateFilterForm, -} from "../interfaces/index.js"; -import { OtherPresetsSection } from "../Other/OtherPresetsSection.js"; -import { RelativeDateFilterFormSection } from "../RelativeDateFilterForm/RelativeDateFilterFormSection.js"; -import { - type CalendarTabType, - getDefaultCalendarTab, - getFilteredGranularities, - getFilteredPresets, - getFiscalTabsConfig, -} from "../utils/presetFilterUtils.js"; - -import { AbsolutePresetFilterItems } from "./AbsolutePresetFilterItems.js"; -import { CalendarTypeTabs } from "./CalendarTypeTabs.js"; -import { RelativePresetFilterItems } from "./RelativePresetFilterItems.js"; -import { type DateFilterRoute } from "./types.js"; - -const ITEM_CLASS_MOBILE = "gd-date-filter-item-mobile"; - -interface IDateFilterBodyContentProps { - filterOptions: IDateFilterOptionsByType; - selectedFilterOption: DateFilterOption; - isMobile: boolean; - route: DateFilterRoute; - dateFormat: string; - isTimeForAbsoluteRangeEnabled: boolean; - isSecondsForAbsoluteRangeEnabled?: boolean; - weekStart: WeekStart; - availableGranularities: DateFilterGranularity[]; - errors?: IExtendedDateFilterErrors; - withoutApply?: boolean; - onSelectedFilterOptionChange: (option: DateFilterOption) => void; - closeDropdown: () => void; - changeRoute: (newRoute?: DateFilterRoute) => void; - onApplyClick: () => void; - /** - * Active calendars configuration from workspace settings. - */ - activeCalendars?: IActiveCalendars; - - /** - * Enables empty date values UI (e.g. “Other → Empty values” preset, empty-values handling controls). - * - * @alpha - */ - enableEmptyDateValues?: boolean; -} - -export function DateFilterBodyContent({ - filterOptions, - selectedFilterOption, - isMobile, - route, - errors, - dateFormat, - isTimeForAbsoluteRangeEnabled, - isSecondsForAbsoluteRangeEnabled, - weekStart, - availableGranularities, - withoutApply, - closeDropdown, - changeRoute, - onApplyClick, - onSelectedFilterOptionChange, - activeCalendars, - enableEmptyDateValues, -}: IDateFilterBodyContentProps) { - const intl = useIntl(); - const listboxLabel = intl.formatMessage({ id: "dateFilterDropdown.label" }); - const fiscalTabsConfig = getFiscalTabsConfig(filterOptions.relativePreset, activeCalendars); - - const [selectedTab, setSelectedTab] = useState(() => - getDefaultCalendarTab(activeCalendars, selectedFilterOption), - ); - const tabsIdBase = useIdPrefixed("calendar-tabs"); - const tabIds = { - standard: `${tabsIdBase}-standard-tab`, - fiscal: `${tabsIdBase}-fiscal-tab`, - }; - const panelId = `${tabsIdBase}-panel`; - const activeTabId = selectedTab === "fiscal" ? tabIds.fiscal : tabIds.standard; - - // When the selected option is not visible (e.g. preset from the other tab), - // the first listbox item (AllTime) needs tabIndex={0} so the list is keyboard-reachable. - // Note: relies on AllTime being the first rendered item in the listbox. - const selectedId = selectedFilterOption.localIdentifier; - - const filteredRelativePreset = getFilteredPresets( - filterOptions.relativePreset, - fiscalTabsConfig, - selectedTab, - ); - const filteredAvailableGranularities = getFilteredGranularities( - availableGranularities, - fiscalTabsConfig, - selectedTab, - ); - const isSelectedInVisibleList = - selectedId === filterOptions.allTime?.localIdentifier || - selectedId === filterOptions.emptyValues?.localIdentifier || - selectedId === filterOptions.absoluteForm?.localIdentifier || - selectedId === filterOptions.relativeForm?.localIdentifier || - filterOptions.absolutePreset?.some((p) => p.localIdentifier === selectedId) || - Object.values(filteredRelativePreset ?? {}).some((items) => - items?.some((p) => p.localIdentifier === selectedId), - ); - - const listContent = ( - <> - - - {isEmpty(filteredAvailableGranularities) ? null : ( - - )} - {filterOptions.absolutePreset && filterOptions.absolutePreset.length > 0 ? ( - - ) : null} - {filteredRelativePreset ? ( - - ) : null} - - - ); - - return ( - <> - {fiscalTabsConfig.showTabs ? ( - - ) : null} - {fiscalTabsConfig.showTabs ? ( -
-
- {listContent} -
-
- ) : ( -
- {listContent} -
- )} - - ); -} diff --git a/libs/sdk-ui-filters/src/DateFilter/DateFilterCore.tsx b/libs/sdk-ui-filters/src/DateFilter/DateFilterCore.tsx index fe6da05baa0..60aad8b8ab2 100644 --- a/libs/sdk-ui-filters/src/DateFilter/DateFilterCore.tsx +++ b/libs/sdk-ui-filters/src/DateFilter/DateFilterCore.tsx @@ -325,6 +325,7 @@ export function DateFilterCore({ ignoreClicksOnByClass={[ ".s-do-not-close-dropdown-on-click", ".rdp-day", // absolute range picker calendar items + ".rc-picker-cell-inner", // PeriodRangePicker (rc-picker) period grid cells ]} renderBody={({ closeDropdown, ariaAttributes }) => { return isConfigurationOpen && FilterConfigurationComponent ? ( diff --git a/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.test.tsx b/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.test.tsx deleted file mode 100644 index 7c745ce77eb..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// (C) 2007-2026 GoodData Corporation - -import { fireEvent, render, screen } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; - -import { ArrowButton } from "./ArrowButton.js"; - -describe("ArrowButton", () => { - describe("when not disabled", () => { - it("should not disable the button", () => { - render( {}} arrowDirection="increment" />); - - expect(screen.getByRole("button", { hidden: true })).not.toBeDisabled(); - }); - - it("should call the onClick handler when clicked", () => { - const onClick = vi.fn(); - render(); - - fireEvent.click(screen.getByRole("button", { hidden: true })); - - expect(onClick).toBeCalled(); - }); - }); - - describe("when disabled", () => { - it("should disable the button", () => { - render( {}} arrowDirection="increment" disabled />); - - expect(screen.getByRole("button", { hidden: true })).toBeDisabled(); - }); - - it("should not call the onClick handler when clicked", () => { - const onClick = vi.fn(); - render(); - - fireEvent.click(screen.getByRole("button", { hidden: true })); - - expect(onClick).not.toBeCalled(); - }); - }); -}); diff --git a/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.tsx b/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.tsx deleted file mode 100644 index c92d98f7a38..00000000000 --- a/libs/sdk-ui-filters/src/DateFilter/NumericInput/ArrowButton.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// (C) 2007-2025 GoodData Corporation - -import cx from "classnames"; -import { constant } from "lodash-es"; - -import { unless } from "./utils.js"; - -type ArrowDirection = "increment" | "decrement"; - -const iconClassNames: { [AD in ArrowDirection]: string } = { - decrement: "gd-icon-chevron-down", - increment: "gd-icon-chevron-up", -}; - -export function ArrowButton(props: { - onClick: () => void; - arrowDirection: ArrowDirection; - disabled?: boolean; -}) { - return ( -