From a6f499b69aef4b1e80bffc5ce7afb48eef015110 Mon Sep 17 00:00:00 2001 From: Ross Kukulinski Date: Fri, 8 Sep 2023 02:32:00 -0700 Subject: [PATCH] Main (#20) * refactor(product): rename product version attribute to name (#2) * docs(readme): update konnect free trial url (#3) * Add issue template (#5) * test(catalog): breakup chaining in catalog pagination tests (#6) * refactor(auth): revert to v1 of auth api (#4) * refactor(auth): revert to v1 of auth api * test(auth): fix tests for auth Need to use the v1 api endpoints until kauth deploys v2 endpoints in production --------- Co-authored-by: Nathan Bailey * chore(ci): parallelize tests in ci (#9) * ci: dependabot integration (#8) * build(deps): bump eslint-plugin-promise from 4.3.1 to 6.1.1 (#10) Bumps [eslint-plugin-promise](https://github.com/eslint-community/eslint-plugin-promise) from 4.3.1 to 6.1.1. - [Release notes](https://github.com/eslint-community/eslint-plugin-promise/releases) - [Changelog](https://github.com/eslint-community/eslint-plugin-promise/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-community/eslint-plugin-promise/compare/v4.3.1...v6.1.1) --- updated-dependencies: - dependency-name: eslint-plugin-promise dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * ci: lint before tests (#20) * build(deps): bump vue-router from 4.1.6 to 4.2.1 (#11) Bumps [vue-router](https://github.com/vuejs/router) from 4.1.6 to 4.2.1. - [Release notes](https://github.com/vuejs/router/releases) - [Commits](https://github.com/vuejs/router/compare/v4.1.6...v4.2.1) --- updated-dependencies: - dependency-name: vue-router dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build: advise to use yarn instead of npm (TDX-3164) (#21) * chore: clean comments and resolve issues [TDX-3087] (#7) * chore(styles): remove TODOs around placeholder text * chore(styles): fix darkmode styling in modals * refactor(auth): auth card redirect to home when public portal Co-authored-by: Mike Swierenga * refactor(catalog): update search response properties (#23) * chore(docs): steps to disable commit formatting (#22) * build(deps): bump eslint-plugin-vue from 9.9.0 to 9.14.1 (#24) Bumps [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) from 9.9.0 to 9.14.1. - [Release notes](https://github.com/vuejs/eslint-plugin-vue/releases) - [Commits](https://github.com/vuejs/eslint-plugin-vue/compare/v9.9.0...v9.14.1) --- updated-dependencies: - dependency-name: eslint-plugin-vue dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump lefthook from 1.4.0 to 1.4.1 (#17) Bumps [lefthook](https://github.com/evilmartians/lefthook) from 1.4.0 to 1.4.1. - [Release notes](https://github.com/evilmartians/lefthook/releases) - [Changelog](https://github.com/evilmartians/lefthook/blob/master/CHANGELOG.md) - [Commits](https://github.com/evilmartians/lefthook/compare/v1.4.0...v1.4.1) --- updated-dependencies: - dependency-name: lefthook dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump date-fns from 2.29.3 to 2.30.0 (#16) Bumps [date-fns](https://github.com/date-fns/date-fns) from 2.29.3 to 2.30.0. - [Release notes](https://github.com/date-fns/date-fns/releases) - [Changelog](https://github.com/date-fns/date-fns/blob/v2.30.0/CHANGELOG.md) - [Commits](https://github.com/date-fns/date-fns/compare/v2.29.3...v2.30.0) --- updated-dependencies: - dependency-name: date-fns dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump js-yaml from 3.14.1 to 4.1.0 (#12) Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.14.1 to 4.1.0. - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/3.14.1...4.1.0) --- updated-dependencies: - dependency-name: js-yaml dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @typescript-eslint/parser from 5.54.1 to 5.59.7 (#13) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.54.1 to 5.59.7. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.59.7/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @vue/compiler-sfc from 3.2.47 to 3.3.4 (#27) Bumps [@vue/compiler-sfc](https://github.com/vuejs/core/tree/HEAD/packages/compiler-sfc) from 3.2.47 to 3.3.4. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/commits/v3.3.4/packages/compiler-sfc) --- updated-dependencies: - dependency-name: "@vue/compiler-sfc" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @vue/eslint-config-typescript from 5.1.0 to 11.0.3 (#30) Bumps [@vue/eslint-config-typescript](https://github.com/vuejs/eslint-config-typescript) from 5.1.0 to 11.0.3. - [Release notes](https://github.com/vuejs/eslint-config-typescript/releases) - [Commits](https://github.com/vuejs/eslint-config-typescript/compare/v5.1.0...v11.0.3) --- updated-dependencies: - dependency-name: "@vue/eslint-config-typescript" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump cypress-split from 1.3.7 to 1.3.8 (#33) Bumps [cypress-split](https://github.com/bahmutov/cypress-split) from 1.3.7 to 1.3.8. - [Release notes](https://github.com/bahmutov/cypress-split/releases) - [Commits](https://github.com/bahmutov/cypress-split/compare/v1.3.7...v1.3.8) --- updated-dependencies: - dependency-name: cypress-split dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump eslint-plugin-standard from 4.1.0 to 5.0.0 (#25) Bumps [eslint-plugin-standard](https://github.com/standard/eslint-plugin-standard) from 4.1.0 to 5.0.0. - [Commits](https://github.com/standard/eslint-plugin-standard/compare/v4.1.0...v5.0.0) --- updated-dependencies: - dependency-name: eslint-plugin-standard dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump cypress from 12.11.0 to 12.13.0 (#35) Bumps [cypress](https://github.com/cypress-io/cypress) from 12.11.0 to 12.13.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v12.11.0...v12.13.0) --- updated-dependencies: - dependency-name: cypress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump vue from 3.2.47 to 3.3.4 (#34) Bumps [vue](https://github.com/vuejs/core) from 3.2.47 to 3.3.4. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.2.47...v3.3.4) --- updated-dependencies: - dependency-name: vue dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump eslint from 8.36.0 to 8.41.0 (#36) Bumps [eslint](https://github.com/eslint/eslint) from 8.36.0 to 8.41.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.36.0...v8.41.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump xstate from 4.37.0 to 4.37.2 (#31) Bumps [xstate](https://github.com/statelyai/xstate) from 4.37.0 to 4.37.2. - [Release notes](https://github.com/statelyai/xstate/releases) - [Commits](https://github.com/statelyai/xstate/compare/xstate@4.37.0...xstate@4.37.2) --- updated-dependencies: - dependency-name: xstate dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @typescript-eslint/eslint-plugin from 5.54.1 to 5.59.7 (#39) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.54.1 to 5.59.7. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.59.7/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump tailwindcss from 1.9.6 to 3.3.2 (#32) * build(deps): bump tailwindcss from 1.9.6 to 3.3.2 Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss) from 1.9.6 to 3.3.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/master/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/compare/v1.9.6...v3.3.2) --- updated-dependencies: - dependency-name: tailwindcss dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore: update package json to include autoprefixer --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Ma * build(deps): bump sass from 1.58.3 to 1.62.1 (#29) Bumps [sass](https://github.com/sass/dart-sass) from 1.58.3 to 1.62.1. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.58.3...1.62.1) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong/kongponents from 8.60.1 to 8.67.3 (#26) Bumps [@kong/kongponents](https://github.com/Kong/kongponents) from 8.60.1 to 8.67.3. - [Release notes](https://github.com/Kong/kongponents/releases) - [Changelog](https://github.com/Kong/kongponents/blob/main/CHANGELOG.md) - [Commits](https://github.com/Kong/kongponents/compare/v8.60.1...v8.67.3) --- updated-dependencies: - dependency-name: "@kong/kongponents" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: remove unused markdown-it dependencies (#40) * build(deps): bump eslint-plugin-cypress from 2.12.1 to 2.13.3 (#46) Bumps [eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress) from 2.12.1 to 2.13.3. - [Release notes](https://github.com/cypress-io/eslint-plugin-cypress/releases) - [Commits](https://github.com/cypress-io/eslint-plugin-cypress/compare/v2.12.1...v2.13.3) --- updated-dependencies: - dependency-name: eslint-plugin-cypress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump vite-svg-loader from 3.6.0 to 4.0.0 (#37) Bumps [vite-svg-loader](https://github.com/jpkleemans/vite-svg-loader) from 3.6.0 to 4.0.0. - [Release notes](https://github.com/jpkleemans/vite-svg-loader/releases) - [Commits](https://github.com/jpkleemans/vite-svg-loader/compare/3.6.0...4.0.0) --- updated-dependencies: - dependency-name: vite-svg-loader dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * test: fix flaky catalog spec test (#48) * build(deps): bump @vitejs/plugin-vue-jsx from 2.1.1 to 3.0.1 (#28) Bumps [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue-jsx) from 2.1.1 to 3.0.1. - [Release notes](https://github.com/vitejs/vite-plugin-vue/releases) - [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue-jsx/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue-jsx@3.0.1/packages/plugin-vue-jsx) --- updated-dependencies: - dependency-name: "@vitejs/plugin-vue-jsx" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong/kong-auth-elements from 2.0.0 to 2.0.3 (#41) Bumps [@kong/kong-auth-elements](https://github.com/Kong/kong-auth-elements) from 2.0.0 to 2.0.3. - [Release notes](https://github.com/Kong/kong-auth-elements/releases) - [Changelog](https://github.com/Kong/kong-auth-elements/blob/main/CHANGELOG.md) - [Commits](https://github.com/Kong/kong-auth-elements/compare/v2.0.0...v2.0.3) --- updated-dependencies: - dependency-name: "@kong/kong-auth-elements" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/document-viewer from 0.5.27 to 0.8.0 (#49) Bumps [@kong-ui-public/document-viewer](https://github.com/Kong/public-ui-components/tree/HEAD/packages/portal/document-viewer) from 0.5.27 to 0.8.0. - [Release notes](https://github.com/Kong/public-ui-components/releases) - [Changelog](https://github.com/Kong/public-ui-components/blob/main/packages/portal/document-viewer/CHANGELOG.md) - [Commits](https://github.com/Kong/public-ui-components/commits/@kong-ui-public/document-viewer@0.8.0/packages/portal/document-viewer) --- updated-dependencies: - dependency-name: "@kong-ui-public/document-viewer" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @vue/eslint-config-standard from 5.1.2 to 8.0.1 (#18) * build(deps): bump @vue/eslint-config-standard from 5.1.2 to 8.0.1 Bumps [@vue/eslint-config-standard](https://github.com/vuejs/eslint-config-standard/tree/HEAD/packages/eslint-config-standard) from 5.1.2 to 8.0.1. - [Release notes](https://github.com/vuejs/eslint-config-standard/releases) - [Changelog](https://github.com/vuejs/eslint-config-standard/blob/main/packages/eslint-config-standard/CHANGELOG.md) - [Commits](https://github.com/vuejs/eslint-config-standard/commits/@vue/eslint-config-standard@8.0.1/packages/eslint-config-standard) --- updated-dependencies: - dependency-name: "@vue/eslint-config-standard" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore: fix linting * chore: resolve yarn --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Ma Co-authored-by: David Ma <40131297+davidma415@users.noreply.github.com> * build(deps): bump @vitejs/plugin-vue from 4.1.0 to 4.2.3 (#43) Bumps [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue) from 4.1.0 to 4.2.3. - [Release notes](https://github.com/vitejs/vite-plugin-vue/releases) - [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@4.2.3/packages/plugin-vue) --- updated-dependencies: - dependency-name: "@vitejs/plugin-vue" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pinia from 2.0.33 to 2.1.3 (#45) Bumps [pinia](https://github.com/vuejs/pinia) from 2.0.33 to 2.1.3. - [Release notes](https://github.com/vuejs/pinia/releases) - [Commits](https://github.com/vuejs/pinia/compare/pinia@2.0.33...pinia@2.1.3) --- updated-dependencies: - dependency-name: pinia dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump vite from 4.3.5 to 4.3.9 (#47) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.5 to 4.3.9. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.3.9/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/spec-renderer from 0.7.17 to 0.9.0 (#50) * fix: remove legacy endpoints (#55) * fix: lint actions (#56) * style: wrap text in catalog table view for long descriptions (#54) * refactor: only show empty state if not loading (#53) * build(deps): bump @kong/kongponents from 8.67.3 to 8.70.0 (#51) * chore(deps): bump @kong/kongponents version (#59) * feat: rename "service" to "product" across konnect portal [TDX-3134] (#58) * chore: update dependencies and add lint rule * refactor: add types for LaunchDarkly * feat: rename service -> product behind flag * build(deps): bump eslint from 8.41.0 to 8.42.0 (#69) Bumps [eslint](https://github.com/eslint/eslint) from 8.41.0 to 8.42.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.41.0...v8.42.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Feat/readme update with new product details. (#61) * chore: additional product details to the readme * updated readme to front-end test suite Minor fix Co-authored-by: Henri Pietila --------- Co-authored-by: Henri Pietila * refactor: rename service to product for variables [TDX-3134] (#72) * refactor: rename service to product for variables --------- Co-authored-by: Nathan Bailey * updated readme links (#73) Fix a few broken links, add UTM campaign to registration url * ci: add commitlint as PR check (#74) * build: pin versions (#75) * fix(ci): commitlint checks should ignore dependabot (#78) * build(deps): bump concurrently from 7.6.0 to 8.1.0 (#67) Bumps [concurrently](https://github.com/open-cli-tools/concurrently) from 7.6.0 to 8.1.0. - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](https://github.com/open-cli-tools/concurrently/compare/v7.6.0...v8.1.0) --- updated-dependencies: - dependency-name: concurrently dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: update i18n strings for breadcrumbs (#80) * chore(deps): bump to latest sdk version and fix code (#79) * build: deploy to github pages (#81) Co-authored-by: Andrew Wylde * ci: ghpages deploy (#82) * build(deps): bump cypress from 12.13.0 to 12.14.0 (#84) Bumps [cypress](https://github.com/cypress-io/cypress) from 12.13.0 to 12.14.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v12.13.0...v12.14.0) --- updated-dependencies: - dependency-name: cypress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @commitlint/config-conventional from 17.6.3 to 17.6.5 (#87) Bumps [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) from 17.6.3 to 17.6.5. - [Release notes](https://github.com/conventional-changelog/commitlint/releases) - [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md) - [Commits](https://github.com/conventional-changelog/commitlint/commits/v17.6.5/@commitlint/config-conventional) --- updated-dependencies: - dependency-name: "@commitlint/config-conventional" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: kauth baseUrl handling (#89) * build: optimize cache and node version handling (#88) * build(deps): bump @kong/kongponents from 8.73.1 to 8.78.0 (#86) * build(deps): bump @typescript-eslint/eslint-plugin from 5.59.7 to 5.59.9 (#85) * build(deps): bump @kong-ui-public/document-viewer from 0.8.3 to 0.8.4 (#66) * ci: fix deployment edge cases (#90) * ci: remove caching for cypress tests (#91) * ci: move lint in code-quality step (#92) * fix(dcr): truncate show creds (#94) * build(deps): bump cypress-terminal-report from 4.1.3 to 5.2.0 (#63) Bumps [cypress-terminal-report](https://github.com/archfz/cypress-terminal-report) from 4.1.3 to 5.2.0. - [Commits](https://github.com/archfz/cypress-terminal-report/commits) --- updated-dependencies: - dependency-name: cypress-terminal-report dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Henri Pietila * build(deps): bump sass from 1.62.1 to 1.63.4 (#100) Bumps [sass](https://github.com/sass/dart-sass) from 1.62.1 to 1.63.4. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.62.1...1.63.4) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump concurrently from 8.1.0 to 8.2.0 (#98) Bumps [concurrently](https://github.com/open-cli-tools/concurrently) from 8.1.0 to 8.2.0. - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](https://github.com/open-cli-tools/concurrently/compare/v8.1.0...v8.2.0) --- updated-dependencies: - dependency-name: concurrently dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump eslint-plugin-vue from 9.14.1 to 9.15.0 (#96) Bumps [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) from 9.14.1 to 9.15.0. - [Release notes](https://github.com/vuejs/eslint-plugin-vue/releases) - [Commits](https://github.com/vuejs/eslint-plugin-vue/compare/v9.14.1...v9.15.0) --- updated-dependencies: - dependency-name: eslint-plugin-vue dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * ci: proper permissions (#102) * ci: ignore patch releases (#103) * feat: .editorconfig integration (#104) * build(deps): bump eslint from 8.42.0 to 8.43.0 (#107) Bumps [eslint](https://github.com/eslint/eslint) from 8.42.0 to 8.43.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.42.0...v8.43.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: refactor auth elements to use v2 endpoints (#95) * feat: refactor auth elements to use v2 endpoints * chore: fix by renaming route --------- Co-authored-by: Nathan Bailey * build(deps): bump @kong/kongponents from 8.78.0 to 8.82.2 (#105) * build(deps): bump @typescript-eslint/eslint-plugin from 5.59.9 to 5.60.0 (#108) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.59.9 to 5.60.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.60.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: prevent no .env (#110) * chore: bump spec renderer version for styling (#111) * feat(documents): accept vendored content type (#115) * fix: adjust error handling for auth elements for v2 api (TDX-3212) (#117) * chore(deps): bump sdk-portal-js (#118) * chore(deps): bump sdk-portal-js This incorporates a breaking change where updating an application was previously a PUT but is now a PATCH. * chore(deps): update yarn lock * test(applications): update intercepted request method from PUT to PATCH * chore(deps): bump SDK version to 1.0.0 (#120) * chore(deps): bump SDK version to 1.0.0 * chore(deps): update yarn lock * fix(products): use vnd prefix for content-type * refactor(applications): provide type hint for compiler to match SDK type * test(catalog): update service to product (#124) * Revert "fix: prevent no .env (#110)" (#122) This reverts commit 2cd7b8552017d424da957537763df15d5cac7620. * fix(LD): use featureset for ld (#116) * build(deps): bump @typescript-eslint/parser from 5.59.7 to 5.60.1 (#129) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.59.7 to 5.60.1. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.60.1/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump cypress from 12.14.0 to 12.16.0 (#131) Bumps [cypress](https://github.com/cypress-io/cypress) from 12.14.0 to 12.16.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v12.14.0...v12.16.0) --- updated-dependencies: - dependency-name: cypress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(appreg): add optional chaining to product.name (#135) * style(registration): update registration modal styling (#134) * fix(products-list): fix structure for table header (#144) * build(deps): bump cypress-terminal-report from 5.2.0 to 5.3.2 (#143) Bumps [cypress-terminal-report](https://github.com/archfz/cypress-terminal-report) from 5.2.0 to 5.3.2. - [Commits](https://github.com/archfz/cypress-terminal-report/commits) --- updated-dependencies: - dependency-name: cypress-terminal-report dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump vite from 4.3.9 to 4.4.2 (#142) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.3.9 to 4.4.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.4.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Henri Pietila * build(deps): bump @typescript-eslint/parser from 5.60.1 to 5.61.0 (#138) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.60.1 to 5.61.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.61.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @typescript-eslint/eslint-plugin from 5.60.0 to 5.62.0 (#145) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.60.0 to 5.62.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.62.0/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(vite): ignore css warnings triggered by dependencies (#147) * perf(vite): reduce bundle size via lazy-loaded routes (#146) * build(deps): bump eslint from 8.43.0 to 8.44.0 (#128) Bumps [eslint](https://github.com/eslint/eslint) from 8.43.0 to 8.44.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.43.0...v8.44.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump xstate from 4.37.2 to 4.38.0 (#114) Bumps [xstate](https://github.com/statelyai/xstate) from 4.37.2 to 4.38.0. - [Release notes](https://github.com/statelyai/xstate/releases) - [Commits](https://github.com/statelyai/xstate/compare/xstate@4.37.2...xstate@4.38.0) --- updated-dependencies: - dependency-name: xstate dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Henri Pietila * build(deps): bump vue-tsc from 1.6.5 to 1.8.4 (#139) Bumps [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/vue-tsc) from 1.6.5 to 1.8.4. - [Release notes](https://github.com/vuejs/language-tools/releases) - [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md) - [Commits](https://github.com/vuejs/language-tools/commits/v1.8.4/packages/vue-tsc) --- updated-dependencies: - dependency-name: vue-tsc dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(auth): set the base url on axios client for requests that use raw paths (#149) * chore: bump spec renderer package for styling (#148) * chore: update tailwind.config as purge is deprecated (#150) * chore: update tailwind.config as purge is deprecated * chore: cleanup * feat(i18n): catalan, german, spanish, french locales (#152) * test(*): mock all api endpoints in cypress tests (#151) * chore(flag): remove product naming feature flag (#159) * fix(auth): ensure redirect handler is registered when receiving 401 (#153) * fix(tests): mock LaunchDarkly requests during tests (#160) * test(*): generate uuids with crypto.randomUUID (#158) * build(deps): bump launchdarkly-js-client-sdk from 2.24.2 to 3.1.3 TDX-3216 (#68) * build(deps): bump launchdarkly-js-client-sdk from 2.24.2 to 3.1.3 Bumps [launchdarkly-js-client-sdk](https://github.com/launchdarkly/js-client-sdk) from 2.24.2 to 3.1.3. - [Release notes](https://github.com/launchdarkly/js-client-sdk/releases) - [Changelog](https://github.com/launchdarkly/js-client-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/launchdarkly/js-client-sdk/compare/2.24.2...3.1.3) --- updated-dependencies: - dependency-name: launchdarkly-js-client-sdk dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): update to work with LD3 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: henripro * fix: remove error message in app form when resubmitting (#162) * build(deps): bump cypress from 12.16.0 to 12.17.1 (#155) Bumps [cypress](https://github.com/cypress-io/cypress) from 12.16.0 to 12.17.1. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v12.16.0...v12.17.1) --- updated-dependencies: - dependency-name: cypress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * style: update classes in spec.vue for styling (#163) * build(deps): bump @kong/kongponents from 8.82.2 to 8.85.0 (#140) * build(deps): bump @kong/kongponents from 8.82.2 to 8.85.0 Bumps [@kong/kongponents](https://github.com/Kong/kongponents) from 8.82.2 to 8.85.0. - [Release notes](https://github.com/Kong/kongponents/releases) - [Changelog](https://github.com/Kong/kongponents/blob/main/CHANGELOG.md) - [Commits](https://github.com/Kong/kongponents/compare/v8.82.2...v8.85.0) --- updated-dependencies: - dependency-name: "@kong/kongponents" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(types): explictly set grid | table type * refactor(catalog): explicit type --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: henripro * build(deps): bump eslint from 8.44.0 to 8.45.0 (#154) Bumps [eslint](https://github.com/eslint/eslint) from 8.44.0 to 8.45.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.44.0...v8.45.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(node): update to LTS 18 (#165) * build(deps): bump @kong-ui-public/spec-renderer from 0.9.41 to 0.10.0 (#166) Bumps [@kong-ui-public/spec-renderer](https://github.com/Kong/public-ui-components/tree/HEAD/packages/portal/spec-renderer) from 0.9.41 to 0.10.0. - [Release notes](https://github.com/Kong/public-ui-components/releases) - [Changelog](https://github.com/Kong/public-ui-components/blob/main/packages/portal/spec-renderer/CHANGELOG.md) - [Commits](https://github.com/Kong/public-ui-components/commits/@kong-ui-public/spec-renderer@0.10.0/packages/portal/spec-renderer) --- updated-dependencies: - dependency-name: "@kong-ui-public/spec-renderer" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong/kongponents from 8.85.0 to 8.98.0 (#171) Bumps [@kong/kongponents](https://github.com/Kong/kongponents) from 8.85.0 to 8.98.0. - [Release notes](https://github.com/Kong/kongponents/releases) - [Changelog](https://github.com/Kong/kongponents/blob/main/CHANGELOG.md) - [Commits](https://github.com/Kong/kongponents/compare/v8.85.0...v8.98.0) --- updated-dependencies: - dependency-name: "@kong/kongponents" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump sass from 1.63.4 to 1.64.0 (#167) Bumps [sass](https://github.com/sass/dart-sass) from 1.63.4 to 1.64.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.63.4...1.64.0) --- updated-dependencies: - dependency-name: sass dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/document-viewer from 0.8.4 to 0.9.0 (#169) Bumps [@kong-ui-public/document-viewer](https://github.com/Kong/public-ui-components/tree/HEAD/packages/portal/document-viewer) from 0.8.4 to 0.9.0. - [Release notes](https://github.com/Kong/public-ui-components/releases) - [Changelog](https://github.com/Kong/public-ui-components/blob/main/packages/portal/document-viewer/CHANGELOG.md) - [Commits](https://github.com/Kong/public-ui-components/commits/@kong-ui-public/document-viewer@0.9.0/packages/portal/document-viewer) --- updated-dependencies: - dependency-name: "@kong-ui-public/document-viewer" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/copy-uuid from 0.3.15 to 0.6.0 (#170) Bumps [@kong-ui-public/copy-uuid](https://github.com/Kong/public-ui-components/tree/HEAD/packages/core/copy-uuid) from 0.3.15 to 0.6.0. - [Release notes](https://github.com/Kong/public-ui-components/releases) - [Changelog](https://github.com/Kong/public-ui-components/blob/main/packages/core/copy-uuid/CHANGELOG.md) - [Commits](https://github.com/Kong/public-ui-components/commits/@kong-ui-public/copy-uuid@0.6.0/packages/core/copy-uuid) --- updated-dependencies: - dependency-name: "@kong-ui-public/copy-uuid" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong/kongponents from 8.98.0 to 8.99.0 (#174) Bumps [@kong/kongponents](https://github.com/Kong/kongponents) from 8.98.0 to 8.99.0. - [Release notes](https://github.com/Kong/kongponents/releases) - [Changelog](https://github.com/Kong/kongponents/blob/main/CHANGELOG.md) - [Commits](https://github.com/Kong/kongponents/compare/v8.98.0...v8.99.0) --- updated-dependencies: - dependency-name: "@kong/kongponents" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(ci): add lint and type check as required for tests (#176) * ci: use semantic-release to generate releases and changelog (#175) * ci: check PR title instead of commits (#178) * style(login): update styling of sso button on login view (#179) * build(deps): bump @kong/kong-auth-elements from 2.1.0 to 2.7.1 (#183) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/copy-uuid from 0.6.0 to 0.7.5 (#188) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/document-viewer from 0.9.0 to 0.10.5 (#189) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong-ui-public/spec-renderer from 0.10.0 to 0.11.6 (#190) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @kong/kongponents from 8.99.0 to 8.116.2 (#187) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(ci): update sync-changes.yml to use proper bot token (#191) * fix(auth): update package to fix register request payload (#192) * build(deps): bump eslint-plugin-vue from 9.15.0 to 9.16.1 (#186) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * style: fix css variables for document viewer (#193) * build(deps): bump eslint from 8.45.0 to 8.46.0 (#180) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: improve empty states for spec / doc rendering (#194) * chore: update readme for domain clarification (#195) * feat: add check for meta.public for public routes (#196) * chore(deps): bump portal sdk to 2.1 (#201) * fix: update variable names for document viewer (#203) * feat(app-analytics): expose SDK for application analytics (#204) * build(deps): bump @kong/kong-auth-elements from 2.7.2 to 2.8.0 (#199) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: add information to readme regarding public directory (#205) * build(deps): bump @kong-ui-public/copy-uuid from 0.7.5 to 1.1.5 (#206) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @typescript-eslint/parser from 5.61.0 to 5.62.0 (#156) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump eslint-plugin-import from 2.27.5 to 2.28.0 (#185) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor: dont query catalog if switching views (#208) * refactor: redirect to 404 when spec is not found (#215) * feat(vitals): migrate contextual analytics from monolith [MA-1788] (#133) * fix(analytics): port over the contextual analytics spec (#216) * build(deps): bump eslint from 8.46.0 to 8.47.0 (#212) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @commitlint/config-conventional from 17.6.5 to 17.7.0 (#210) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(analytics): keep peerDependencies in step with workspace version [MA-1977] (#220) * fix: updates spec renderer to fix side nav bug (#224) * fix(locales): switch untranslated strings to english (#223) * build(deps): bump eslint-plugin-vue from 9.16.1 to 9.17.0 (#209) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: update .env.example (#222) * build(deps): bump eslint-plugin-cypress from 2.13.3 to 2.14.0 (#211) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @commitlint/cli from 17.6.3 to 17.7.1 (#214) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump sass from 1.64.0 to 1.66.1 (#219) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @vitejs/plugin-vue from 4.2.3 to 4.3.1 (#217) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump semantic-release from 21.0.7 to 21.1.1 (#228) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: David Ma <40131297+davidma415@users.noreply.github.com> Co-authored-by: devonl-kong <127453992+devonl-kong@users.noreply.github.com> Co-authored-by: Nathan Bailey Co-authored-by: Andrew Wylde Co-authored-by: Vincent Le Goff Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mike Swierenga Co-authored-by: Mike Swierenga Co-authored-by: David Ma Co-authored-by: Henri Pietila Co-authored-by: Adam DeHaven <2229946+adamdehaven@users.noreply.github.com> Co-authored-by: Devon Langendoerfer Co-authored-by: Mihai <103061463+mihai-peteu@users.noreply.github.com> Co-authored-by: Benjamin PATRON --- .client.eslintrc.js | 1 + .editorconfig | 10 + .env.example | 8 +- .../konnect-portal-issue-template.md | 41 + .github/dependabot.yml | 12 + .github/scripts/pin-version | 42 + .github/workflows/check-pr-title.yml | 19 + .github/workflows/github-pages.yml | 56 + .github/workflows/pr.yml | 48 +- .github/workflows/release.yml | 22 + .github/workflows/sync-changes.yml | 23 + .npmrc | 1 + .nvmrc | 1 + .releaserc.yaml | 45 + README.md | 125 +- commitlint.config.js | 1 + cypress.config.js | 17 +- cypress.server.mjs | 11 +- cypress/e2e/fixtures/consts.ts | 33 +- .../e2e/{ => fixtures/images}/kong-logo.png | Bin cypress/e2e/specs/api_documentation.spec.ts | 68 +- .../specs/application_registration.spec.ts | 69 +- cypress/e2e/specs/catalog.spec.ts | 196 +- .../e2e/specs/contextual-analytics.spec.ts | 114 + cypress/e2e/specs/forbidden.spec.ts | 4 +- cypress/e2e/specs/forgot_password.spec.ts | 1 + cypress/e2e/specs/login.spec.ts | 80 +- cypress/e2e/specs/not_found.spec.ts | 4 +- cypress/e2e/specs/portal_auth.spec.ts | 45 +- cypress/e2e/specs/register.spec.ts | 2 + cypress/e2e/specs/reset_password.spec.ts | 33 +- cypress/e2e/specs/spec_renderer.spec.ts | 152 +- cypress/e2e/specs/themeing.spec.ts | 24 +- cypress/e2e/support/index.ts | 51 +- cypress/e2e/support/mock-commands.ts | 174 +- cypress/e2e/support/utils/cookieParser.js | 22 - .../e2e/support/utils/generateDocuments.ts | 9 +- cypress/e2e/support/utils/generateProducts.ts | 21 +- .../support/utils/generateServicePackages.js | 29 - cypress/e2e/tsconfig.json | 15 + lefthook.yaml | 8 +- package.json | 124 +- postcss.config.js | 11 +- src/App.vue | 30 +- src/assets/kongponents-theme.scss | 43 +- src/assets/mixins.scss | 8 + src/assets/utilities.scss | 2 +- src/assets/variables.scss | 6 + .../ApiDocumentation/DocumentTree.vue | 12 +- src/components/AuthCard.vue | 13 +- src/components/AuthValidate.vue | 2 +- src/components/Catalog.vue | 46 +- src/components/CatalogCardList.vue | 14 +- src/components/CatalogItem.vue | 44 +- src/components/CatalogTableList.vue | 52 +- src/components/CopyButton.vue | 8 +- src/components/DisplayNameModal.vue | 7 + src/components/ErrorWrapper.vue | 4 +- src/components/Nav.vue | 2 +- src/components/UserDropdown.vue | 10 +- src/components/ViewSpecModal.vue | 2 +- src/components/ViewSpecRegistrationModal.vue | 29 +- .../{service => product}/Sidebar.vue | 31 +- .../{service => product}/sidebar/Section.vue | 0 .../sidebar/SectionOverview.vue | 16 +- .../sidebar/SectionReference.vue | 17 +- src/components/registerComponents.ts | 2 + src/components/vitals/AnalyticsEmptyState.vue | 57 + .../vitals/AnalyticsMetricsCard.vue | 68 + src/components/vitals/ChartPanel.vue | 279 + src/components/vitals/MetricsProvider.vue | 82 + src/composables/useAllowedTimeframes.ts | 60 + src/composables/useChartQueryBuilder.ts | 26 + src/composables/useChartRequest.ts | 52 + src/composables/useLaunchDarkly.ts | 43 +- src/constants/chartQueries.ts | 73 + src/constants/feature-flags.ts | 4 +- src/helpers/auth.ts | 18 + src/helpers/handleKongAuthElementsError.ts | 20 +- src/helpers/snakeToCamelCase.ts | 17 + src/hooks/useKongAuthApi.ts | 10 - src/hooks/useLDFeatureFlag.ts | 10 +- src/hooks/usePortalApi.ts | 4 +- src/locales/README.md | 25 + src/locales/ca_ES.ts | 310 + src/locales/de.ts | 310 + src/locales/en.ts | 144 +- src/locales/es_ES.ts | 310 + src/locales/fr.ts | 310 + src/locales/i18n-type.d.ts | 306 + src/locales/index.ts | 24 +- src/main.ts | 30 +- src/router/index.ts | 328 +- src/services/ApiService.ts | 136 - .../{KongAuthApi.ts => AuthApiService.ts} | 27 +- src/services/PortalV2ApiService.ts | 9 +- src/services/SessionCookie.ts | 25 +- src/services/index.ts | 21 +- src/stores/app.ts | 19 +- src/stores/i18n.ts | 18 +- src/stores/product.ts | 7 +- src/types/productVersion.ts | 9 + src/types/vitals.ts | 19 + src/views/ApiDocumentationPage.vue | 91 +- .../Applications/ApplicationDashboard.vue | 367 + src/views/Applications/ApplicationDetail.vue | 69 +- src/views/Applications/ApplicationForm.vue | 23 +- src/views/Applications/CredentialsList.vue | 14 +- .../{ServiceList.vue => ProductList.vue} | 45 +- src/views/Forbidden.vue | 2 +- src/views/Login.vue | 85 +- src/views/MyApps.vue | 82 +- src/views/NotFound.vue | 2 +- ...Services.vue => ProductCatalogWrapper.vue} | 71 +- .../{ServiceShell.vue => ProductShell.vue} | 108 +- src/views/Registration.vue | 21 +- src/views/ResetPassword.vue | 5 +- src/views/Spec.vue | 121 +- tailwind.config.js | 15 +- tsconfig.json | 9 +- vite.config.js | 65 +- yarn.lock | 7632 ++++++++++++----- 122 files changed, 10409 insertions(+), 3800 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/ISSUE_TEMPLATE/konnect-portal-issue-template.md create mode 100644 .github/dependabot.yml create mode 100755 .github/scripts/pin-version create mode 100644 .github/workflows/check-pr-title.yml create mode 100644 .github/workflows/github-pages.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/sync-changes.yml create mode 100644 .npmrc create mode 100644 .nvmrc create mode 100644 .releaserc.yaml rename cypress/e2e/{ => fixtures/images}/kong-logo.png (100%) create mode 100644 cypress/e2e/specs/contextual-analytics.spec.ts delete mode 100644 cypress/e2e/support/utils/cookieParser.js delete mode 100644 cypress/e2e/support/utils/generateServicePackages.js create mode 100644 cypress/e2e/tsconfig.json create mode 100644 src/assets/mixins.scss create mode 100644 src/assets/variables.scss rename src/components/{service => product}/Sidebar.vue (70%) rename src/components/{service => product}/sidebar/Section.vue (100%) rename src/components/{service => product}/sidebar/SectionOverview.vue (67%) rename src/components/{service => product}/sidebar/SectionReference.vue (87%) create mode 100644 src/components/vitals/AnalyticsEmptyState.vue create mode 100644 src/components/vitals/AnalyticsMetricsCard.vue create mode 100644 src/components/vitals/ChartPanel.vue create mode 100644 src/components/vitals/MetricsProvider.vue create mode 100644 src/composables/useAllowedTimeframes.ts create mode 100644 src/composables/useChartQueryBuilder.ts create mode 100644 src/composables/useChartRequest.ts create mode 100644 src/constants/chartQueries.ts create mode 100644 src/helpers/auth.ts create mode 100644 src/helpers/snakeToCamelCase.ts delete mode 100644 src/hooks/useKongAuthApi.ts create mode 100644 src/locales/README.md create mode 100644 src/locales/ca_ES.ts create mode 100644 src/locales/de.ts create mode 100644 src/locales/es_ES.ts create mode 100644 src/locales/fr.ts create mode 100644 src/locales/i18n-type.d.ts delete mode 100644 src/services/ApiService.ts rename src/services/{KongAuthApi.ts => AuthApiService.ts} (86%) create mode 100644 src/types/productVersion.ts create mode 100644 src/types/vitals.ts create mode 100644 src/views/Applications/ApplicationDashboard.vue rename src/views/Applications/{ServiceList.vue => ProductList.vue} (84%) rename src/views/{Services.vue => ProductCatalogWrapper.vue} (77%) rename src/views/{ServiceShell.vue => ProductShell.vue} (66%) diff --git a/.client.eslintrc.js b/.client.eslintrc.js index ab68e87f..0e69ac2d 100644 --- a/.client.eslintrc.js +++ b/.client.eslintrc.js @@ -13,6 +13,7 @@ module.exports = { '@vue/typescript' ], rules: { + "vue/no-bare-strings-in-template": ["error"], 'arrow-parens': 'off', 'generator-star-spacing': 'off', 'object-property-newline': 'error', diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ba2d7765 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf + +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.env.example b/.env.example index adce8448..5c2d860c 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,11 @@ -# URL for portal api +# URL for portal api. Note URL must end with a trailing slash. VITE_PORTAL_API_URL='https://developer.konghq.com/' # Sets the localization, defaults to 'en' if unset VITE_LOCALE='en' + +# Sets whether LaunchDarkly is enabled within the portal, defaults to false if unset +VITE_ENABLE_LAUNCH_DARKLY=true + +# sets whether to create a visualization of the current project's dependency graph, defaults to false if unset +BUILD_VISUALIZER=false diff --git a/.github/ISSUE_TEMPLATE/konnect-portal-issue-template.md b/.github/ISSUE_TEMPLATE/konnect-portal-issue-template.md new file mode 100644 index 00000000..e229f32c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/konnect-portal-issue-template.md @@ -0,0 +1,41 @@ +--- +name: konnect-portal-issue-template +about: Konnect-Portal Issue +title: '' +labels: '' +assignees: '' + +--- + + + +## Expected Behavior + + + +## Current Behavior + + + +## Possible Solution + + + +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + +## Your Environment + +* Version used: +* Browser Name and version: +* Operating System and version (desktop or mobile): +* Link to your project: diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5b8ade8d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + commit-message: + prefix: build(deps) + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-patch"] diff --git a/.github/scripts/pin-version b/.github/scripts/pin-version new file mode 100755 index 00000000..81e342d8 --- /dev/null +++ b/.github/scripts/pin-version @@ -0,0 +1,42 @@ +#!/usr/bin/env node + +// ensure that no unpinned version lands in the package.json +const path = require('path') +const pkgFileDir = (process.argv.length >= 3) ? process.argv[2] : "." +const pkgFilePath = path.resolve(pkgFileDir, "package.json") + +console.log(`Loading ${pkgFilePath}`) +const pkg = require(pkgFilePath) + +function checkPackage(pkg) { + const errors = [] + + errors.push(...checkPinned(pkg.dependencies)) + errors.push(...checkPinned(pkg.devDependencies)) + + return errors +} + +function checkPinned(obj) { + const errors = [] + + for (const dep in obj) { + if (obj[dep].startsWith('^') || obj[dep].startsWith('~') || obj[dep].toLowerCase().includes('.x') || obj[dep] === '*') { + errors.push(`${dep}:${obj[dep]}`) + } + } + + return errors +} + +const errors = checkPackage(pkg) + +if(errors.length) { + console.error(`Unpinned deps in ${pkgFilePath}`) + errors.forEach(x=>console.error(x)) + + process.exit(1) +} else { + console.log(`No unpinned deps in ${pkgFilePath}`) + process.exit(0) +} diff --git a/.github/workflows/check-pr-title.yml b/.github/workflows/check-pr-title.yml new file mode 100644 index 00000000..bedaa8e4 --- /dev/null +++ b/.github/workflows/check-pr-title.yml @@ -0,0 +1,19 @@ +name: Check PR title + +on: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + +jobs: + lint: + runs-on: ubuntu-latest + permissions: + statuses: write + steps: + - uses: aslafy-z/conventional-pr-title-action@v3 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml new file mode 100644 index 00000000..c37e7c2f --- /dev/null +++ b/.github/workflows/github-pages.yml @@ -0,0 +1,56 @@ +name: Deploy on Kong github-pages + +# This is a workflow to deploy konnect-portal using github pages +# This one will build the UI to use the api located https://api-konnect-portal.konghq.com +# And will be resolved by the CNAME konnect-portal.konghq.com +# If you want to implement this please see the following workflow and its explanations + +on: + workflow_dispatch: + push: + branches: + - main + +jobs: + deploy: + # This permission is required on the first run of running the action on a branch + # because the branch doesn't exist the workflow needs permission to create it + permissions: + contents: write + if: github.repository == 'kong/konnect-portal' + name: deploy build to github-pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: node modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ hashFiles('.nvmrc', 'yarn.lock') }} + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: generate env file + # generating the environment file to have our final build + # This is likely to be adjustred for your needs + run: | + echo "VITE_PORTAL_API_URL='https://api-konnect-portal.konghq.com/'" >> .env + echo "VITE_LOCALE='en'" >> .env + echo "VITE_ENABLE_LAUNCH_DARKLY=true" >> .env + - name: Lint + run: yarn lint + - name: Build + run: yarn build + # See documentation of the github action below + # ref: https://github.com/peaceiris/actions-gh-pages/tree/v3 + - name: Deploy to github pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated github token + publish_branch: gh-pages # the branch where you want the dist to be published + publish_dir: ./dist # this is the output directory of `yarn build` command + cname: konnect-portal.konghq.com # the cname to be resolved for the UI + force_orphan: true # this will clean the commit history of the `gh-pages` branch diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index ea97c4b7..d5c9d405 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -4,19 +4,57 @@ on: pull_request: jobs: + code-quality: + name: Lint and type check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Check unpinned versions + run: ./.github/scripts/pin-version + - name: node modules cache + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ hashFiles('.nvmrc', 'yarn.lock') }} + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + - name: Install Dependencies + run: yarn install --frozen-lockfile + - name: Lint + run: yarn lint + - name: Check TypeScript types + run: yarn typecheck tests: name: Tests runs-on: ubuntu-latest + needs: code-quality + strategy: + fail-fast: false + matrix: + containers: [1, 2, 3] steps: - uses: actions/checkout@v3 - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: '16.19.0' + node-version-file: '.nvmrc' - name: Install dependencies - run: yarn install + run: yarn install --frozen-lockfile - name: Copy .env.example run: cp .env.example .env - - name: Run tests - run : | - yarn test:e2e:ci + - name: Build + run: yarn build + # run 3 copies of the current job in parallel + - name: Run split Cypress tests 🧪 + uses: cypress-io/github-action@v5 + with: + start: node cypress.server.mjs + browser: chrome + # pass the machine index and the total number + env: + SPLIT: ${{ strategy.job-total }} + SPLIT_INDEX: ${{ strategy.job-index }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..6dfe9177 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +name: Semantic Release +on: + workflow_dispatch: +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: yarn install --frozen-lockfile + - name: Semantic Release + env: + GITHUB_TOKEN: ${{ secrets.GHA_TEAM_DEVX_KONG_BOT_PAT }} + run: npx semantic-release diff --git a/.github/workflows/sync-changes.yml b/.github/workflows/sync-changes.yml new file mode 100644 index 00000000..b1477be8 --- /dev/null +++ b/.github/workflows/sync-changes.yml @@ -0,0 +1,23 @@ +name: Sync Changes From Release Tag +on: + release: + types: published +jobs: + merge: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: release + fetch-depth: 0 + token: ${{ secrets.GHA_TEAM_DEVX_KONG_BOT_PAT }} + - name: Override release branch with changes from release tag + shell: bash + env: + GH_TOKEN: ${{ secrets.GHA_TEAM_DEVX_KONG_BOT_PAT }} + run: | + git config --global user.email "team-devx+github-bot@konghq.com" + git config --global user.name "team-devx" + git reset --hard ${{ github.event.release.tag_name }} + git push --force-with-lease origin release diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..c42da845 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict = true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..6d80269a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18.16.0 diff --git a/.releaserc.yaml b/.releaserc.yaml new file mode 100644 index 00000000..2fccea5d --- /dev/null +++ b/.releaserc.yaml @@ -0,0 +1,45 @@ +{ + "branches": ["main"], + "tagFormat": "${version}", + "plugins": [ + ["@semantic-release/commit-analyzer", { + "preset": "conventionalcommits", + "releaseRules": [ + { "breaking": true, "release": "major" }, + { "revert": true, "release": "patch" }, + { "type": "build", "release": "patch" }, + { "type": "chore", "release": "patch" }, + { "type": "docs", "release": "patch" }, + { "type": "feat", "release": "minor" }, + { "type": "fix", "release": "patch" }, + { "type": "perf", "release": "patch" }, + { "type": "refactor", "release": "patch" } + ] + }], + ["@semantic-release/release-notes-generator", { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { "type": "build", "section": "Build", "hidden": false }, + { "type": "chore", "section": "Chores", "hidden": false }, + { "type": "ci", "section": "CI/CD", "hidden": false }, + { "type": "docs", "section": "Docs", "hidden": false }, + { "type": "feat", "section": "Features", "hidden": false }, + { "type": "fix", "section": "Bug Fixes", "hidden": false }, + { "type": "perf", "section": "Performance", "hidden": false }, + { "type": "refactor", "section": "Refactor", "hidden": false }, + { "type": "style", "section": "Code Style", "hidden": false }, + { "type": "test", "section": "Tests", "hidden": false } + ] + } + }], + "@semantic-release/github", + ["@semantic-release/git", { + "assets": ["CHANGELOG.md", "package.json", "yarn.lock"], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + }], + "@semantic-release/changelog" + ], + "successComment": false +} + diff --git a/README.md b/README.md index 1ab92828..104c53d8 100644 --- a/README.md +++ b/README.md @@ -7,22 +7,73 @@ ![License](https://img.shields.io/badge/License-Apache%202.0-blue?style=flat-square) ![Twitter Follow](https://img.shields.io/twitter/follow/thekonginc?style=social) + # Konnect Dev Portal Client -This repo is the [OSS][oss-url] Konnect Dev Portal Client, you may use this as a starting point for you own custom Konnect Dev Portal that consumes the Konnect Portal API. +This repo is an [open source][oss-url] reference implementation of a Konnect Developer Portal Client leveraging the [Konnect Developer Portal Client API][portal-api-url] and [JavaScript SDK][javscript-sdk-url]. + +The [Konnect Dev Portal][konnect-docs-url] is a web application for developers to locate, access, and consume API services. The Dev Portal enables developers to browse and search API documentation, test API endpoints, and manage their own credentials. + +In [Kong Konnect][kong-konnect-register-url], you have two hosting options for the Dev Portal web user interface: a cloud hosted Dev Portal with Konnect or a self-hosted, open source Dev Portal powered by Konnect APIs. + +## Self-hosted Dev Portal benefits + +There are several benefits to keep in mind when deciding whether to use a Konnect-hosted or self-hosted Dev Portal. The self-hosted portal provides the following benefits: + +* Fully customizable: Use the example frontend Dev Portal application as a starting point and then customize Dev Portal for your needs using the Portal API. You can also integrate the API specs with workflows tailored to your organization’s own processes. +* Hosting service choice: When you self-host, you also get to choose which hosting service you use to deploy your Dev Portal. +* Range of customization options: With the self-hosted Dev Portal, you determine how much you want to customize. You can choose to use the example application right out of the box or you can use the Portal API to have more fine-grained control. +* Configurable internationalization +* Automated front-end test suite powered by Cypress + +With those benefits in mind, there _is_ the hosting cost to deploy this single page portal and you may need developer/designer support to fully customize this modern web-application to meet your business requirements. + ## Getting started -### Prerequisites: +### Using the Project: Best Practices + +### Branches + +1. **Main Branch (`main`)**: The `main` branch serves as the default branch, and all commits and pull requests should be directed here. It represents the latest version of the project. + +2. **Release Branch (`release`)**: The `release` branch includes all the changes from the `main` branch, but its latest commit will always correspond to the latest release tag. + +### Choosing the Right Branch + +When contributing or using the project, it is essential to understand which branch best suits your needs: + +1. **For Contributors**: + +* If you want to contribute any new features or bug fixes, please create a new branch based on the `main` branch. Name your branch descriptively ([see the branch naming conventions](#branch-naming-conventions) - Open a pull request to merge your changes into the `main` branch. This allows the maintainers to review your code before merging it into the default branch. + +2. **For Users Who Want Frequent Updates**: + +* If you prefer to use the latest development version of the project, you should use the `main` branch directly, either in your fork or as a submodule of your project. + +3. **For Users Who Want Stable Releases**: + +* Use the `release` branch if you prefer less-frequent updates. - The `release` branch provides a production-ready version of the project at each tagged release. - It is recommended to keep your fork of the repository updated with the latest changes from the `release` branch. + +### Staying Updated + +Whether you are contributing or using the project, staying updated is crucial: + +* Regularly fetch and pull changes from the `main` branch to your local repository. This ensures that your work is based on the most recent codebase. +* If you are using the `release` branch, merge the latest changes from `main` into your fork periodically to keep it up-to-date with the latest releases. + +By following these guidelines, both contributors and users can efficiently collaborate on and use the project, ensuring a smooth and productive development experience for everyone involved. + +### Prerequisites * Kong Konnect account - * You can Start a Free trial at: [konghq.com][kong-konnect-register-url] - * Documentation for Kong Konnect is available at: [docs.konghq.com][konnect-docs-url] -* Yarn [^1.22.x][yarn-install url] + * You can Start a Free trial at: [konghq.com][kong-konnect-register-url] + * Documentation for Kong Konnect is available at: [docs.konghq.com][konnect-docs-url] +* Yarn [^1.22.x][yarn-install-url] Install dependencies ```sh -yarn +yarn install --frozen-lockfile ``` Create local .env file @@ -31,7 +82,7 @@ Create local .env file cp .env.example .env ``` -Set `VITE_PORTAL_API_URL` value in your current environment i.e .env file or local environment, this should match either the Kong supplied portal URL ending in `portal.konghq.com` or the [custom Portal URL set in Konnect][custom-dev-portal-url]. Be sure to set the Custom Client domain to match the domain you will be serving the portal out of to avoid CORS issues. +Set `VITE_PORTAL_API_URL` value in your current environment i.e .env file or local environment, this should match either the Kong supplied portal URL ending in `portal.konghq.com` (for local development) or the [custom hosted domain URL set in Konnect][custom-dev-portal-url] (for your deployed environment). Be sure to set the custom self-hosted UI domain to match the domain you will be serving the portal out of to avoid CORS issues. For Development you can provide any portal API URL, it is proxied by Vite, so you do not need to set the custom client domain. @@ -42,10 +93,15 @@ yarn dev #optional --verbose ``` Run tests with + ```sh yarn test:e2e ``` +### Public Directory + +If you need to store assets (e.g. fonts, images, or icons), you can create a `public` directory at the root level of the repository and Vite will utilize it by default. For more information on when or how to use the public folder, visit [here](https://vitejs.dev/guide/assets.html#the-public-directory). + ## Building for production release Build production bundle '_(dist/)_' for deployment with @@ -61,27 +117,48 @@ First and foremost please and comply with the standards outlined in the [CODE_OF ### Committing Changes - Please follow the following branch naming scheme when creating your branch: This repo uses [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). [Commitizen](https://github.com/commitizen/cz-cli) can be used to help build commit messages. + Please follow the following branch naming scheme when creating your branch: This repo uses [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). [Commitizen](https://github.com/commitizen/cz-cli) can be used to help build commit messages. Or you can utilize the installed version with any of the following commands: + + ```sh + yarn commit + ``` + +#### _Note:_ + _To disable linting during the `pre-push` git hook (on your fork), you can either comment out the contents of the lefthook.yaml file or remove it, as well as uninstall lefthook from the package.json file._ + + i.e - ### Branch naming conventions + ```sh + $ rm lefthook.yaml + $ yarn remove lefthook + ``` + +### Branch naming conventions Please follow the following branch naming scheme when creating your branch: -- `feat/foo-bar` for new features -- `fix/foo-bar` for bug fixes -- `test/foo-bar` when the change concerns only the test suite -- `refactor/foo-bar` when refactoring code without any behavior change -- `style/foo-bar` when addressing some style issue -- `docs/foo-bar` for updates to the README.md, this file, or similar documents +* `feat/foo-bar` for new features +* `fix/foo-bar` for bug fixes +* `test/foo-bar` when the change concerns only the test suite +* `refactor/foo-bar` when refactoring code without any behavior change +* `style/foo-bar` when addressing some style issue +* `docs/foo-bar` for updates to the README.md, this file, or similar documents +* `ci/foo-bar` for updates to the GitHub workflows or actions + +## Releases + +This repo uses [Semantic Release](https://github.com/semantic-release/semantic-release) for automated releases once per week. The release is triggered by a GitHub Action on the `main` branch. The release is based on the commit messages, so please follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification. + +## [Translations guidelines](./src/locales/README.md) ## Join the Community -- Join the Kong discussions at the Kong Nation forum: [https://discuss.konghq.com/](https://discuss.konghq.com/) -- Follow us on Twitter: [https://twitter.com/thekonginc](https://twitter.com/thekonginc) -- Check out the docs: [https://docs.konghq.com/](https://docs.konghq.com/) -- Keep updated on YouTube by subscribing: [https://www.youtube.com/c/KongInc/videos](https://www.youtube.com/c/KongInc/videos) -- Read up on the latest happenings at our blog: [https://konghq.com/blog/](https://konghq.com/blog/) -- Visit our homepage to learn more: [https://konghq.com/](https://konghq.com/) +* Join the Kong discussions at the Kong Nation forum: [https://discuss.konghq.com/](https://discuss.konghq.com/) +* Follow us on Twitter: [https://twitter.com/thekonginc](https://twitter.com/thekonginc) +* Check out the docs: [https://docs.konghq.com/](https://docs.konghq.com/) +* Keep updated on YouTube by subscribing: [https://www.youtube.com/c/KongInc/videos](https://www.youtube.com/c/KongInc/videos) +* Read up on the latest happenings at our blog: [https://konghq.com/blog/](https://konghq.com/blog/) +* Visit our homepage to learn more: [https://konghq.com/](https://konghq.com/) ## License @@ -102,9 +179,11 @@ limitations under the License. ``` [custom-dev-portal-url]: https://docs.konghq.com/konnect/dev-portal/customization/#custom-dev-portal-url -[kong-konnect-register-url]: https://konghq.com/products/kong-konnect/register?utm_medium=referral&utm_source=docs&utm_campaign=gateway-konnect&utm_content=top-nav +[kong-konnect-register-url]: https://konghq.com/products/kong-konnect/register?utm_medium=referral&utm_source=github&utm_campaign=gateway-konnect&utm_content=konnect-portal-readme +[portal-api-url]: https://developer.konghq.com/spec/2aad2bcb-8d82-43b3-abdd-1d5e6e84dbd6/b4539157-4ced-4df5-affa-7d790baee356 [kong-logo-url]: https://konghq.com/wp-content/uploads/2018/05/kong-logo-github-readme.png [kong-url]: https://konghq.com/ [konnect-docs-url]: https://docs.konghq.com/konnect/ [oss-url]: https://en.wikipedia.org/wiki/Open-source_software -[yarn-install url]: https://classic.yarnpkg.com/lang/en/docs/install +[yarn-install-url]: https://classic.yarnpkg.com/lang/en/docs/install +[javscript-sdk-url]: https://www.npmjs.com/package/@kong/sdk-portal-js diff --git a/commitlint.config.js b/commitlint.config.js index 6f0da658..a4a3ba52 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,5 +1,6 @@ module.exports = { extends: ['@commitlint/config-conventional'], + ignores: [(message) => /^Bumps \[.+]\(.+\) from .+ to .+\.$/m.test(message)], // from https://github.com/dependabot/dependabot-core/issues/2445#issuecomment-949633412 rules: { 'header-max-length': [2, 'always', 108] } diff --git a/cypress.config.js b/cypress.config.js index 72c4be0f..34eac053 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,9 +1,23 @@ const { defineConfig } = require('cypress') +const cypressSplit = require('cypress-split') +const dotenv = require('dotenv') + +dotenv.config() module.exports = defineConfig({ e2e: { setupNodeEvents (on, config) { require('cypress-terminal-report/src/installLogsPrinter')(on) + cypressSplit(on, config) + + config.env = { + ...process.env, + ...config.env + } + + + // IMPORTANT: return the config object + return config }, baseUrl: 'http://localhost:8088', specPattern: 'cypress/e2e/specs/*.spec.(js|ts)', @@ -17,11 +31,10 @@ module.exports = defineConfig({ fixturesFolder: 'cypress/e2e/fixtures', includeShadowDom: true, reporter: 'spec', - retries: 2, screenshotsFolder: 'cypress/e2e/screenshots', scrollBehavior: 'center', trashAssetsBeforeRuns: false, videoCompression: false, videosFolder: 'cypress/e2e/videos', - watchForFileChanges: false + watchForFileChanges: true }) diff --git a/cypress.server.mjs b/cypress.server.mjs index af0a7c21..218f54f5 100644 --- a/cypress.server.mjs +++ b/cypress.server.mjs @@ -9,16 +9,7 @@ const __dirname = path.resolve() app.use(express.static('dist', { index: false })) app.use(express.json()) -app.get('/portal_assets/logo', (req, res) => { - res.sendFile( - path.join( - __dirname, - './cypress/e2e.kong-logo.png' - ) - ) -}) - -app.get(/^\/(?!portal_api|kauth).*/, (req, res) => { +app.get(/^\/(?!kauth).*/, (req, res) => { res.status(200).sendFile(path.join(__dirname, './dist/index.html')) }) diff --git a/cypress/e2e/fixtures/consts.ts b/cypress/e2e/fixtures/consts.ts index 41394b4d..5eedc7ab 100644 --- a/cypress/e2e/fixtures/consts.ts +++ b/cypress/e2e/fixtures/consts.ts @@ -1,12 +1,11 @@ import { GetApplicationResponse, GetRegistrationResponse, PortalContext, Product, ProductVersion } from '@kong/sdk-portal-js' -import { v4 as uuidv4 } from 'uuid' const versions: ProductVersion[] = [ { created_at: '2022-03-26T14:52:46.323Z', updated_at: '2022-03-26T14:52:46.323Z', id: '1afac832-5b2a-474c-a56d-c241364f41cf', - version: 'v1-beta', + name: 'v1-beta', deprecated: false, registration_configs: [{ name: 'key-auth' }] } @@ -15,10 +14,15 @@ const versions: ProductVersion[] = [ const product: Product = { created_at: '2022-03-23T14:52:41.893Z', updated_at: '2022-03-23T14:52:41.893Z', - id: 'a5afb115-025e-4da1-a013-bf05b326e0a51', + id: '29985c03-a866-46f2-8152-29406243b90f', name: 'barAPI', description: null, - labels: {} + document_count: 0, + latest_version: { + id: versions[0].id, + name: versions[0].name + }, + version_count: 1 } const productVersion: ProductVersion = { @@ -31,14 +35,14 @@ const apps: GetApplicationResponse[] = [ name: 'My Cool App', description: 'My Cool App has a cool description', reference_id: '1', - id: uuidv4(), + id: crypto.randomUUID(), created_at: '2022-03-25T13:15:02.104Z', updated_at: '2022-03-25T13:15:02.104Z' }, { name: 'My Other App', reference_id: '2', - id: uuidv4(), + id: crypto.randomUUID(), created_at: '2022-03-25T13:15:02.104Z', updated_at: '2022-03-25T13:15:02.104Z', description: 'My Other App has a cool description' @@ -47,7 +51,7 @@ const apps: GetApplicationResponse[] = [ name: 'My Other Other App', description: 'My Other Other App has a cool description', reference_id: '3', - id: uuidv4(), + id: crypto.randomUUID(), created_at: '2022-03-25T13:15:02.104Z', updated_at: '2022-03-25T13:15:02.104Z' }, @@ -56,13 +60,13 @@ const apps: GetApplicationResponse[] = [ description: 'My DCR App has a cool description', reference_id: '4', redirect_uri: 'http://google.com', - id: uuidv4(), + id: crypto.randomUUID(), created_at: '2022-03-25T13:15:02.104Z', updated_at: '2022-03-25T13:15:02.104Z' } ] -const serviceRegistration: GetRegistrationResponse = { +const productRegistration: GetRegistrationResponse = { created_at: '2022-03-25T13:15:02.104Z', updated_at: '2022-03-25T13:15:02.104Z', id: 'f3081666-e388-41ac-a6c0-9f37de2c2102', @@ -71,7 +75,7 @@ const serviceRegistration: GetRegistrationResponse = { product_id: product.id, product_name: product.name, product_version_id: productVersion.id, - product_version_name: productVersion.version + product_version_name: productVersion.name } const defaultContext: PortalContext = { @@ -82,7 +86,12 @@ const defaultContext: PortalContext = { basic_auth_enabled: true, oidc_auth_enabled: false, featureset_id: '6202956f054d96149719eed0', - rbac_enabled: false + rbac_enabled: false, + allowed_time_period: '2022-03-25T13:15:02.104Z' } -export { versions, product, productVersion, serviceRegistration, apps, defaultContext } +const productRegistrations: GetRegistrationResponse[] = [ + productRegistration +] + +export { versions, product, productVersion, productRegistration, productRegistrations, apps, defaultContext } diff --git a/cypress/e2e/kong-logo.png b/cypress/e2e/fixtures/images/kong-logo.png similarity index 100% rename from cypress/e2e/kong-logo.png rename to cypress/e2e/fixtures/images/kong-logo.png diff --git a/cypress/e2e/specs/api_documentation.spec.ts b/cypress/e2e/specs/api_documentation.spec.ts index 9eba99f2..26bd14f5 100644 --- a/cypress/e2e/specs/api_documentation.spec.ts +++ b/cypress/e2e/specs/api_documentation.spec.ts @@ -1,32 +1,44 @@ -import { product as servicePackage, productVersion as serviceVersion } from '../fixtures/consts' +import { product, productVersion } from '../fixtures/consts' import childrenApiDocumentationJSON from '../fixtures/dochub_mocks/childrenApiDocumentation.json' import documentTreeJSON from '../fixtures/dochub_mocks/documentTree.json' describe('Api Documentation Page', () => { beforeEach(() => { + product.document_count = 1 cy.mockPrivatePortal() - cy.mockServicePackage(servicePackage.id) - cy.mockGetServicePackageDocumentBySlug(servicePackage.id, 'bar') - cy.mockGetServicePackageDocuments(servicePackage.id) - cy.mockServiceOperations() + cy.mockProduct(product.id, product) + cy.mockGetProductDocumentBySlug(product.id, 'bar') + cy.mockGetProductDocuments(product.id) + cy.mockProductOperations() + cy.mockStylesheetFont() }) - const PARENT_DOCUMENT_URL = `/docs/${servicePackage.id}/${documentTreeJSON[0].slug}` + const PARENT_DOCUMENT_URL = `/docs/${product.id}/${documentTreeJSON[0].slug}` const CHILD_DOCUMENT_URL = `${PARENT_DOCUMENT_URL}/${documentTreeJSON[0].children[0].slug}` + it('displays empty state when no products', () => { + product.document_count = 0 + cy.mockProduct(product.id, product) + cy.mockProductDocumentTree(product.id, { body: [] }) + cy.visit(`/docs/${product.id}`) + + cy.get('[data-testid="documentation-empty-state"]').should('be.visible') + cy.get('[data-testid="portal-document-viewer"]').should('not.exist') + }) + it('displays proper error message when 400', () => { cy.intercept( 'GET', - `**/api/v2/products/${servicePackage.id}/documents/foo`, + `**/api/v2/products/${product.id}/documents/foo`, { statusCode: 400, body: {} } - ).as('fetchServicePackageDocument') + ).as('fetchProductDocument') - cy.visit(`/docs/${servicePackage.id}/foo`) + cy.visit(`/docs/${product.id}/foo`) - cy.wait('@fetchServicePackageDocument') + cy.wait('@fetchProductDocument') cy.get('[data-testid="api-documentation-page"]').should('be.visible') cy.get('[data-testid="error-wrapper"]').should('be.visible') @@ -35,27 +47,27 @@ describe('Api Documentation Page', () => { it('redirect when 404', () => { cy.intercept( 'GET', - `**/api/v2/products/${servicePackage.id}/documents/foo`, + `**/api/v2/products/${product.id}/documents/foo`, { statusCode: 404, body: {} } - ).as('fetchServicePackageDocument') + ).as('fetchProductDocument') - cy.visit(`/docs/${servicePackage.id}/foo`) + cy.visit(`/docs/${product.id}/foo`) - cy.wait('@fetchServicePackageDocument') + cy.wait('@fetchProductDocument') cy.location('pathname').should('equal', '/404') }) - it('shows correct document tree in left sidebar of the catalog page for each service', () => { - cy.mockServiceDocument() + it('shows correct document tree in left sidebar of the catalog page for each product', () => { + cy.mockProductDocument() cy.mockProductVersionSpec() - cy.mockServicePackageDocumentTree() + cy.mockProductDocumentTree() - cy.visit(`/spec/${servicePackage.id}/${serviceVersion.id}`) - cy.wait('@getMockServicePackageDocumentTree') + cy.visit(`/spec/${product.id}/${productVersion.id}`) + cy.wait('@getMockProductDocumentTree') // verify if the parent document link is shown cy.get('a.title').contains('a', 'This is the parent document') @@ -72,14 +84,14 @@ describe('Api Documentation Page', () => { it('navigates to the correct API documentation page from Spec view using sidebar', () => { cy.mockProductVersionSpec() - cy.mockServicePackageDocumentTree() - cy.mockServicePackageApiDocument() + cy.mockProductDocumentTree() + cy.mockProductApiDocument() - cy.visit(`/spec/${servicePackage.id}/${serviceVersion.id}`) - cy.wait('@getMockServicePackageDocumentTree') + cy.visit(`/spec/${product.id}/${productVersion.id}`) + cy.wait('@getMockProductDocumentTree') cy.get('a.title').contains('a', 'This is the parent document').click() - cy.wait('@getMockServicePackageApiDocument') + cy.wait('@getMockProductApiDocument') cy.url().should('include', PARENT_DOCUMENT_URL) cy.get('.k-breadcrumb-text').last().should('include.text', 'Documentation') @@ -89,7 +101,7 @@ describe('Api Documentation Page', () => { }) it('shows correct document content', () => { - cy.mockServicePackageApiDocument() + cy.mockProductApiDocument() cy.visit(PARENT_DOCUMENT_URL) @@ -116,13 +128,13 @@ describe('Api Documentation Page', () => { }) it('scrolls to the correct heading when a link is clicked in sidebar', () => { - cy.mockServicePackageDocumentTree() + cy.mockProductDocumentTree() // mock parent - cy.mockServicePackageApiDocument(servicePackage.id, { + cy.mockProductApiDocument(product.id, { body: documentTreeJSON[0] }) // mock child - cy.mockServicePackageApiDocument(servicePackage.id, { + cy.mockProductApiDocument(product.id, { body: childrenApiDocumentationJSON }) diff --git a/cypress/e2e/specs/application_registration.spec.ts b/cypress/e2e/specs/application_registration.spec.ts index 561c92d3..90db3ab0 100644 --- a/cypress/e2e/specs/application_registration.spec.ts +++ b/cypress/e2e/specs/application_registration.spec.ts @@ -1,5 +1,5 @@ import { CredentialCreationResponse, GetApplicationResponse, ListCredentialsResponse, ListCredentialsResponseDataInner, ListRegistrationsResponse } from '@kong/sdk-portal-js' -import { product, versions, serviceRegistration, apps } from '../fixtures/consts' +import { product, versions, productRegistration, apps } from '../fixtures/consts' const mockApplicationWithCredAndReg = ( data: GetApplicationResponse, @@ -54,16 +54,16 @@ Cypress.Commands.add('createNewApplication', (app, productId, versions) => { const submitButton = 'button[type="submit"]' cy.viewport(1440, 900) - cy.mockServicePackageDocumentTree(productId) - cy.mockServiceDocument(productId) + cy.mockProductDocumentTree(productId) + cy.mockProductDocument(productId) cy.mockApplications([], 0) cy.mockRegistrations(app.id) - cy.mockServicePackage(productId, product, versions) + cy.mockProduct(productId, product, versions) cy.mockProductVersionSpec(productId, versions[0].id) - cy.mockServiceOperations(productId, versions[0].id, versions[0].operations) + cy.mockProductOperations(productId, versions[0].id, versions[0].operations) - cy.mockServiceVersionApplicationRegistration(versions[0]) + cy.mockProductVersionApplicationRegistration(versions[0]) cy.intercept('POST', '**/api/v2/applications', { body: { @@ -118,6 +118,10 @@ describe('Application Registration', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockAppearance() + cy.mockStylesheetCss() + cy.mockStylesheetFont() + cy.mockContextualAnalytics() }) it('displays empty dashboard for my apps', () => { @@ -163,9 +167,12 @@ describe('Application Registration', () => { } }).as('postApplicationRegistration') mockApplicationWithCredAndReg(apps[3]) + mockApplicationWithCredAndReg(apps[0]) cy.get(submitButton).click() + + cy.wait('@postApplicationRegistration').then(() => { cy.get('[data-testid="copy-secret-modal"]').should('exist') cy.get('[data-testid="copy-button"]').eq(0).should('exist').should('contain', 'your-client-id') @@ -215,16 +222,18 @@ describe('Application Registration', () => { }) it('can return to My Apps from application details via breadcrumb', () => { + cy.mockDeveloperRefresh() cy.mockApplications(apps, 4) + // navigate directly to My Apps cy.visit('/my-apps') + mockApplicationWithCredAndReg(apps[0]) + // go to application details cy.get('[data-testid="applications-table"] tbody tr') .contains(apps[0].name) .click() - mockApplicationWithCredAndReg(apps[0]) - - cy.mockApplications(apps, 4) + // use breadcrumb to navigate back to My Apps cy.get('.k-breadcrumbs .k-breadcrumbs-item a').contains('My Apps').click() cy.url().should('include', 'my-apps') }) @@ -243,7 +252,7 @@ describe('Application Registration', () => { cy.get('[data-testid="application-name-input"]').type('{end}z', { delay: 0 }) - cy.intercept('PUT', `api/v2/applications/${apps[0].id}`, { + cy.intercept('PATCH', `api/v2/applications/${apps[0].id}`, { statusCode: 200, body: { ...apps[0], name: apps[0].name + 'z' } }).as('getApplicationPatch') @@ -478,12 +487,12 @@ describe('Application Registration', () => { }) describe('Registration Management', () => { - it('can request registration to a service', () => { - cy.mockServiceDocument() - cy.mockServicePackage() - cy.mockServiceVersionApplicationRegistration(versions[0]) - cy.mockGetServicePackageDocuments(product.id) - cy.mockServiceOperations(product.id, versions[0].id) + it('can request registration to a product', () => { + cy.mockProductDocument() + cy.mockProduct() + cy.mockProductVersionApplicationRegistration(versions[0]) + cy.mockGetProductDocuments(product.id) + cy.mockProductOperations(product.id, versions[0].id) cy.mockProductVersionSpec(product.id, versions[0].id) cy.mockRegistrations('*', []) // mock with empty so that we add one. @@ -498,7 +507,7 @@ describe('Application Registration', () => { cy.get(`${selectors.appRegModal} select`).should('contain', apps[0].name) const mockCreateRegResponse = { - ...serviceRegistration, + ...productRegistration, status: 'pending', application: apps[0] } @@ -518,12 +527,12 @@ describe('Application Registration', () => { ) }) - it('can request registration to a service and is directed to application upon auto_approval', () => { - cy.mockServiceDocument() - cy.mockServicePackage() - cy.mockServiceVersionApplicationRegistration(versions[0]) - cy.mockGetServicePackageDocuments(product.id) - cy.mockServiceOperations(product.id, versions[0].id) + it('can request registration to a product and is directed to application upon auto_approval', () => { + cy.mockProductDocument() + cy.mockProduct() + cy.mockProductVersionApplicationRegistration(versions[0]) + cy.mockGetProductDocuments(product.id) + cy.mockProductOperations(product.id, versions[0].id) cy.mockProductVersionSpec(product.id, versions[0].id) cy.mockRegistrations('*', []) @@ -540,16 +549,16 @@ describe('Application Registration', () => { 'POST', `/api/v2/applications/${apps[0].id}/registrations*`, { - body: serviceRegistration + body: productRegistration } ).as('postApplicationRegistration') - mockApplicationWithCredAndReg(apps[1], [], [serviceRegistration]) + mockApplicationWithCredAndReg(apps[1], [], [productRegistration]) cy.get('[data-testid="submit-registration"]').click() - cy.get('[data-testid="services-list"]') - cy.get('[data-testid="services-list"]').should('contain', 'barAPI') + cy.get('[data-testid="products-list"]') + cy.get('[data-testid="products-list"]').should('contain', 'barAPI') cy.get('[data-testid="status-badge"]').should('contain', 'approved') }) @@ -557,13 +566,13 @@ describe('Application Registration', () => { cy.createNewApplication(apps[2], product.id, versions) cy.viewport(1440, 900) - cy.mockServiceDocument() + cy.mockProductDocument() cy.visit(`/spec/${product.id}`).get('.swagger-ui', { timeout: 12000 }) cy.get('[data-testid="register-button"]', { timeout: 12000 }) - cy.mockRegistrations(apps[0].id, [serviceRegistration]) - cy.mockRegistrations(apps[1].id, [serviceRegistration]) + cy.mockRegistrations(apps[0].id, [productRegistration]) + cy.mockRegistrations(apps[1].id, [productRegistration]) cy.mockApplications( [ diff --git a/cypress/e2e/specs/catalog.spec.ts b/cypress/e2e/specs/catalog.spec.ts index 93422666..30a9381d 100644 --- a/cypress/e2e/specs/catalog.spec.ts +++ b/cypress/e2e/specs/catalog.spec.ts @@ -1,19 +1,34 @@ import { SearchResults, SearchResultsDataInner } from '@kong/sdk-portal-js' -import { v4 as uuidv4 } from 'uuid' import { generateProducts } from '../support/utils/generateProducts' -const mockServiceSearchQuery = (searchQuery: string) => { - const searchResults: SearchResultsDataInner[] = [ - ['barAPI', ['v1-beta'], uuidv4()], - ['fooApi', ['v1'], uuidv4()], - ['sampleapi', ['v1'], uuidv4()], - ['testapi', ['v1'], uuidv4()], - ['xapi', ['v1'], uuidv4()] - ] +const mockProductSearchQuery = (searchQuery: string) => { + const searchResults: SearchResultsDataInner[] = ([ + ['barAPI', ['v1-beta']], + ['fooApi', ['v1']], + ['sampleapi', ['v1']], + ['testapi', ['v1']], + ['xapi', ['v1']] + ] as [string, string[]][]) .filter((data) => searchQuery !== '' ? JSON.stringify(data).includes(searchQuery) : true ) - .map(([name, versions, id]) => ({ index: 'product-catalog', source: { description: '', has_documentation: false, created_at: '', updated_at: '', name, versions, id } })) + .map(([name, versions]) => ({ + index: 'product-catalog', + source: { + id: crypto.randomUUID(), + description: '', + document_count: 0, + created_at: '', + updated_at: '', + name, + version_count: versions.length, + latest_version: { + name: versions[0], + id: crypto.randomUUID() + } + } + })) + const responseBody: SearchResults = { data: searchResults, meta: { @@ -26,13 +41,14 @@ const mockServiceSearchQuery = (searchQuery: string) => { } cy.intercept('GET', '**/api/v2/search/product-catalog**', { + times: 1, statusCode: 200, body: responseBody, delay: 0 }).as('productSearch') } -const mockServiceSearchResults = (searchResults:SearchResultsDataInner[], pageNumber: number, totalCount:number) => { +const mockProductSearchResults = (searchResults:SearchResultsDataInner[], pageNumber: number, totalCount:number) => { const responseBody: SearchResults = { data: searchResults, meta: { @@ -52,6 +68,12 @@ const mockServiceSearchResults = (searchResults:SearchResultsDataInner[], pageNu } describe('Catalog', () => { + beforeEach(() => { + cy.mockStylesheetFont() + cy.mockAppearance() + cy.mockStylesheetCss() + }) + describe('Catalog card view', () => { beforeEach(() => { cy.mockPublicPortal() @@ -60,25 +82,29 @@ describe('Catalog', () => { cy.visit('/') }) - it('loads one service package with details', () => { + it('loads one product with details', () => { cy.get('.catalog-item').should('have.length', 1) - cy.get('.catalog-item').should('contain', 'barAPI') - cy.get('.catalog-item').should('contain', 'v2') + cy.get('.catalog-item').should('contain', 'barAPI0') + cy.get('.catalog-item').should('contain', 'v0') cy.get('.catalog-item').should('contain', 'great description') - cy.title().should('eq', 'Service Catalog | Developer Portal') + }) + + it('sets the catalog title', () => { + cy.get('.products-label').should('contain', 'Product') + cy.title().should('eq', 'Product Catalog | Developer Portal') }) it('goes to details view on header click', () => { cy.mockPublicPortal() - cy.mockServicePackage() + cy.mockProduct() - cy.get('.catalog-item .services-card-title').first().click() + cy.get('.catalog-item .products-card-title').first().click() cy.url().should('include', '/spec') }) it('goes to details view on specification link click', () => { cy.mockPublicPortal() - cy.mockServicePackage() + cy.mockProduct() cy.mockProductsCatalog(1, [{ description: 'great description' }]) cy.visit('/') @@ -87,28 +113,28 @@ describe('Catalog', () => { cy.url().should('include', '/spec') }) - it('displays an empty state with no services', () => { + it('displays an empty state with no products', () => { cy.mockPublicPortal() cy.mockProductsCatalog(0) cy.visit('/') - cy.get('.serv-catalog-no-services').should('have.length', 1) + cy.get('.product-catalog-no-products').should('have.length', 1) }) - it('disables view switcher with no services', () => { + it('disables view switcher with no products', () => { cy.mockPublicPortal() cy.mockProductsCatalog(0) cy.visit('/') - cy.get('.serv-catalog-no-services').should('have.length', 1) + cy.get('.product-catalog-no-products').should('have.length', 1) cy.get('[data-testid="view-switcher"]').should('be.disabled') }) it('renders the documentation link for catalog item', () => { cy.mockPrivatePortal() - cy.mockProductsCatalog(1, [{ description: 'great description', has_documentation: true }]) + cy.mockProductsCatalog(1, [{ description: 'great description', document_count: 2 }]) cy.visit('/') cy.get('.catalog-item .link').contains('Documentation').should('exist') }) @@ -132,14 +158,14 @@ describe('Catalog', () => { it('goes to details view on click', () => { cy.get('.k-table tbody td:nth-of-type(1)').first().click() - cy.mockServicePackage() + cy.mockProduct() cy.url().should('include', '/spec') }) it('renders the documentation link for catalog item ', () => { cy.mockPrivatePortal() - cy.mockProductsCatalog(1, [{ description: 'great description', has_documentation: true }]) - + cy.mockProductsCatalog(1, [{ description: 'great description', document_count: 1 }]) + cy.mockProduct() cy.visit('/') cy.wait('@productSearch').then(() => { @@ -158,26 +184,15 @@ describe('Catalog', () => { it('displays most recent created_at version', () => { cy.mockProductsCatalog(1, [{ - versions: [ - { - created_at: '2022-03-23T12:41:09.371Z', - updated_at: '2022-03-23T12:41:09.371Z', - id: '6159b9be-bfbc-4f30-bd22-df720f6dcf90', - version: 'v4', - deprecated: false - }, - { - created_at: '2022-03-23T11:46:35.613Z', - updated_at: '2022-03-23T11:46:35.613Z', - id: 'b820d3eb-5b70-47e5-8d97-9436a8021282', - version: 'v1-beta', - deprecated: false - } - ] + version_count: 2, + latest_version: { + id: '6159b9be-bfbc-4f30-bd22-df720f6dcf90', + name: 'v4' + } }]) cy.visit('/') - cy.get('.service-version').should('have.length', 1).contains('v4') + cy.get('.product-version').should('have.length', 1).contains('v4') cy.get('[data-testid="view-switcher"]:not(:disabled)') .click() .get('.k-table tbody tr:first-child td:nth-child(3)') @@ -188,29 +203,18 @@ describe('Catalog', () => { it('displays most recent created_at regardless of version name', () => { cy.mockProductsCatalog(1, [{ - versions: [ - { - created_at: '2022-03-23T12:41:09.371Z', - updated_at: '2022-03-23T12:41:09.371Z', - id: '6159b9be-bfbc-4f30-bd22-df720f6dcf90', - version: 'v4', - deprecated: false - }, - { - created_at: '2022-03-24T11:46:35.613Z', - updated_at: '2022-03-24T11:46:35.613Z', - id: 'b820d3eb-5b70-47e5-8d97-9436a8021282', - version: 'v1-beta', - deprecated: false - } - ] + version_count: 2, + latest_version: { + id: '6159b9be-bfbc-4f30-bd22-df720f6dcf90', + name: 'v4' + } }]) cy.visit('/') cy.get('[data-testid="view-switcher"]:not(:disabled)') .click() .get('.k-table tbody tr:first-child td:nth-child(3)') .should('have.length', 1) - .contains('v1-beta') + .contains('v4') cy.get('[data-testid="view-switcher"]:not(:disabled)').click() }) }) @@ -218,18 +222,18 @@ describe('Catalog', () => { describe('Catalog search', () => { beforeEach(() => { cy.mockPublicPortal() - mockServiceSearchQuery('') + mockProductSearchQuery('') cy.visit('/') }) - it('loads all service packages', () => { + it('loads all product packages', () => { cy.get('.catalog-item').should('have.length', 5) }) it('searches when search button clicked', () => { const searchQuery = 'x' - mockServiceSearchQuery(searchQuery) + mockProductSearchQuery(searchQuery) cy.get('[data-testid=catalog-search]').type(searchQuery) cy.get('[data-testid=catalog-search-button]').click() @@ -242,7 +246,7 @@ describe('Catalog', () => { it('searches when {enter} is typed', () => { const searchQuery = 'x' - mockServiceSearchQuery(searchQuery) + mockProductSearchQuery(searchQuery) cy.get('[data-testid=catalog-search]').type(searchQuery + '{enter}') cy.wait('@productSearch').then(() => { @@ -254,7 +258,7 @@ describe('Catalog', () => { it('shows multiple results when searching', () => { const searchQuery = 's' - mockServiceSearchQuery(searchQuery) + mockProductSearchQuery(searchQuery) cy.get('[data-testid=catalog-search]').type(searchQuery) cy.get('[data-testid=catalog-search-button]').click() cy.wait('@productSearch').then(() => { @@ -266,14 +270,14 @@ describe('Catalog', () => { it('updates table entries when searching', () => { const searchQuery = 's' - mockServiceSearchQuery('') + mockProductSearchQuery('') cy.get('[data-testid=catalog-search]').type('{enter}') cy.get('[data-testid="view-switcher"]:not(:disabled)') .click() .get('.k-table tbody td:nth-of-type(1)') .should('have.length', 5) - mockServiceSearchQuery(searchQuery) + mockProductSearchQuery(searchQuery) cy.get('[data-testid=catalog-search]').type(searchQuery) cy.get('[data-testid=catalog-search]').type('{enter}') cy.wait('@productSearch').then(() => { @@ -283,14 +287,14 @@ describe('Catalog', () => { it('updates the table entries when clearing the field', () => { const searchQuery = 's' - mockServiceSearchQuery(searchQuery) + mockProductSearchQuery(searchQuery) cy.get('[data-testid=catalog-search]').type(searchQuery) cy.get('[data-testid=catalog-search]').type('{enter}') cy.get('[data-testid="view-switcher"]:not(:disabled)').click() cy.wait('@productSearch').then(() => { cy.get('.k-table tbody td:nth-of-type(1)').should('have.length', 2) }) - mockServiceSearchQuery('') + mockProductSearchQuery('') cy.get('[data-testid=catalog-search]').trigger('search') cy.wait('@productSearch').then(() => { cy.get('.k-table tbody td:nth-of-type(1)').should('have.length', 5) @@ -298,9 +302,9 @@ describe('Catalog', () => { }) }) - describe('Create a lot of services', () => { - const totalServiceCount = 37 - const servicesData = generateProducts(37) + describe('Create a lot of products', () => { + const totalProductCount = 37 + const productsData = generateProducts(37) describe('Catalog search', () => { beforeEach(() => { @@ -308,24 +312,24 @@ describe('Catalog', () => { cy.mockAppearance() }) - it('shows 12 services', () => { - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + it('shows 12 products', () => { + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.visit('/') cy.get('.catalog-item').should('have.length', 12) }) it('does not display pagination bar if few enough results', () => { cy.visit('/') - mockServiceSearchResults(servicesData.slice(12, 24), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(12, 24), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]') .click() - .get('.card-pagination-bar') + cy.get('.card-pagination-bar') .contains('13 - 24 of 37') const searchQuery = 'barAPI22' - mockServiceSearchResults( - servicesData.filter((s) => s.source.name === searchQuery), + mockProductSearchResults( + productsData.filter((s) => s.source.name === searchQuery), 1, 1 ) @@ -344,18 +348,18 @@ describe('Catalog', () => { }) it('returns to first page on search', () => { - mockServiceSearchResults(servicesData, 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.visit('/') cy.get('[data-testid=catalog-search]').type('{enter}') - mockServiceSearchResults(servicesData.slice(12, 24), 2, totalServiceCount) + mockProductSearchResults(productsData.slice(12, 24), 2, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]') .click() - .get('.card-pagination-bar') + cy.get('.card-pagination-bar') .contains('13 - 24 of 37') const searchQuery = 'API' - mockServiceSearchResults(servicesData.slice(0, 12), 1, 13) + mockProductSearchResults(productsData.slice(0, 12), 1, 13) cy.get('[data-testid=catalog-search]').type(searchQuery + '{enter}') cy.wait('@productSearch') .its('response.url') @@ -370,18 +374,18 @@ describe('Catalog', () => { }) it('sets offset back to 0 when switching to table view', () => { - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.visit('/') cy.get('[data-testid=catalog-search]').type('{enter}') - mockServiceSearchResults(servicesData.slice(12, 24), 2, totalServiceCount) + mockProductSearchResults(productsData.slice(12, 24), 2, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]') .click() - .get('.card-pagination-bar') + cy.get('.card-pagination-bar') .contains('13 - 24 of 37') cy.get('[data-testid="view-switcher"]:not(:disabled)').click() - mockServiceSearchResults(servicesData.slice(0, 12), 2, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 2, totalProductCount) cy.wait('@productSearch') .its('response.url') .should('contain', 'page%5Bnumber%5D=1') @@ -391,11 +395,11 @@ describe('Catalog', () => { describe('Catalog card list pagination', () => { beforeEach(() => { cy.mockPublicPortal() - cy.mockProductsCatalog(totalServiceCount) + cy.mockProductsCatalog(totalProductCount) }) - it('shows 12 services', () => { - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + it('shows 12 products', () => { + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.visit('/') cy.wait('@productSearch').then(() => { cy.get('.catalog-item').should('have.length', 12) @@ -408,19 +412,19 @@ describe('Catalog', () => { it('allows next page and back', () => { // forwards - mockServiceSearchResults(servicesData.slice(0, 12), 2, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 2, totalProductCount) cy.visit('/') cy.get('.card-pagination-bar [data-testid=pagination-forwards]').click() cy.get('.card-pagination-bar').contains('13 - 24 of 37') // backwards - mockServiceSearchResults(servicesData.slice(0, 12), 12, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 12, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-backwards]').click() cy.get('.card-pagination-bar') .contains('1 - 12 of 37') .get('.catalog-item') .should('have.length', 12) // to last page - mockServiceSearchResults(servicesData.slice(0, 1), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 1), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]') .click() .get('.card-pagination-bar [data-testid=pagination-forwards]') @@ -438,12 +442,12 @@ describe('Catalog', () => { it('allows go to first page and go to last page', () => { cy.visit('/') // forwards - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]').click() - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-forwards]').click() // to first page - mockServiceSearchResults(servicesData.slice(0, 12), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 12), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-first]') .click() .get('.card-pagination-bar') @@ -451,7 +455,7 @@ describe('Catalog', () => { .get('.catalog-item') .should('have.length', 12) // to last page - mockServiceSearchResults(servicesData.slice(0, 1), 1, totalServiceCount) + mockProductSearchResults(productsData.slice(0, 1), 1, totalProductCount) cy.get('.card-pagination-bar [data-testid=pagination-last]') .click() .get('.card-pagination-bar') diff --git a/cypress/e2e/specs/contextual-analytics.spec.ts b/cypress/e2e/specs/contextual-analytics.spec.ts new file mode 100644 index 00000000..cd58a9d3 --- /dev/null +++ b/cypress/e2e/specs/contextual-analytics.spec.ts @@ -0,0 +1,114 @@ +import { apps, productRegistration, productRegistrations, versions } from '../fixtures/consts' + +describe('Contextual Developer Analytics', () => { + beforeEach(() => { + cy.mockPrivatePortal() + cy.mockApplications(apps, 4) + cy.intercept('POST', '**/api/v2/stats*', { + statusCode: 200, + body: { + records: [] + }, + delay: 0 + }) + }) + + const selectors = { + chartsParent: '[data-testid="analytics-charts"]', + dashboardDropdownLink: '[data-testid="dropdown-analytics-dashboard"]', + dateTimePicker: '[data-testid="analytics-timepicker"]', + metricCardsParent: '[data-testid="analytics-metric-cards"]', + viewAnalyticsButton: '[data-testid="application-dashboard-button"]' + } + + it('My Apps – displays displays metric cards if the feature flag is on', () => { + cy.mockLaunchDarklyFlags([{ name: 'ma-1002-dev-portal-contextual-analytics', value: true }]) + + cy.mockApplications(apps, 4) + + cy.visit('/', { useOriginalFn: true }) + cy.visit('/my-apps') + + cy.get(selectors.metricCardsParent).should('exist') + cy.get(selectors.metricCardsParent).find('.metricscard').should('have.length', 3) + + cy.get('[data-testid="applications-table"]').find('.actions-badge').first().click() + cy.get(selectors.dashboardDropdownLink).should('exist') + }) + + it('My Apps – does not display metric cards or the analytics dropdown link if the feature flag is off', () => { + cy.mockLaunchDarklyFlags([{ name: 'ma-1002-dev-portal-contextual-analytics', value: false }]) + + cy.mockApplications(apps, 5) + cy.visit('/my-apps') + + cy.get(selectors.metricCardsParent).should('not.exist') + cy.get('[data-testid="applications-table"]').find('.actions-badge').first().click() + cy.get(selectors.dashboardDropdownLink).should('not.exist') + }) + + it('My App details page – does not display Metrics Card, View Analytics button if the feature flag is off', () => { + cy.mockLaunchDarklyFlags([{ name: 'ma-1002-dev-portal-contextual-analytics', value: true }]) + cy.mockApplications(apps, 4) + + cy.intercept( + 'GET', + `**/api/v2/applications/${apps[0].id}`, { + statusCode: 200, + body: { ...apps[0] } + } + ).as('getSingleApplication') + + cy.mockApplicationWithCredAndReg(apps[0]) + + cy.visit(`/application/${apps[0].id}`) + cy.get('[data-testid="analytics-metric-cards"]').should('not.exist') + cy.get('[data-testid="application-dashboard-button"]').should('not.exist') + }) + + it('App Dashboard - vitals elements load when contextual analytics feature flag is on', () => { + cy.mockLaunchDarklyFlags([{ name: 'ma-1002-dev-portal-contextual-analytics', value: true }]) + cy.mockApplications(apps, 4) + + cy.intercept('GET', `**/api/v2/applications/${apps[0].id}`, { + statusCode: 200, + body: apps[0], + delay: 0 + }).as('getSingleApplication') + + cy.intercept( + 'GET', + `**/api/v2/applications/${apps[0].id}/registrations*`, + { + body: { + data: productRegistrations, + meta: { + page: { + total: 1, + number: 1, + size: 1 + } + } + }, + delay: 0 + } + ).as('getApplicationRegistration') + + cy.visit('/my-apps') + + // Navigate to Application Dashboard page + cy.get('[data-testid="applications-table"]').find('.actions-badge').first().click() + cy.get(selectors.dashboardDropdownLink).first().click() + + // All application dashboard elements should be present + cy.get('.analytics-filters').should('exist') + cy.get(selectors.metricCardsParent).should('exist') + cy.get(selectors.chartsParent).should('exist') + + // Check that the Service Versions filter bar contains at least one item + const mockedServiceVersionName = `${productRegistrations[0].product_name} - ${productRegistrations[0].product_version_name}` + + cy.get('[data-testid="k-multiselect-input"]').should('exist').click() + cy.get('.k-multiselect-item').first().should('contain', mockedServiceVersionName) + }) +}) diff --git a/cypress/e2e/specs/forbidden.spec.ts b/cypress/e2e/specs/forbidden.spec.ts index 023c2256..2e991ff0 100644 --- a/cypress/e2e/specs/forbidden.spec.ts +++ b/cypress/e2e/specs/forbidden.spec.ts @@ -1,6 +1,7 @@ describe('Forbidden Page', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockStylesheetFont() }) it('shows a "forbidden" page', () => { @@ -10,8 +11,9 @@ describe('Forbidden Page', () => { }) it('allows able to move to home using button', () => { + cy.mockProductsCatalog() cy.visit('/403') cy.get('[data-testid="go-home"]').click() - cy.get('.services-welcome').should('exist') + cy.get('.products-welcome').should('exist') }) }) diff --git a/cypress/e2e/specs/forgot_password.spec.ts b/cypress/e2e/specs/forgot_password.spec.ts index 24393963..18cf12c8 100644 --- a/cypress/e2e/specs/forgot_password.spec.ts +++ b/cypress/e2e/specs/forgot_password.spec.ts @@ -1,6 +1,7 @@ describe('Forgot Password Page', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockStylesheetFont() }) it('has link from login page', () => { diff --git a/cypress/e2e/specs/login.spec.ts b/cypress/e2e/specs/login.spec.ts index 3853c77a..1df7b925 100644 --- a/cypress/e2e/specs/login.spec.ts +++ b/cypress/e2e/specs/login.spec.ts @@ -1,10 +1,9 @@ -import { versions } from '../fixtures/consts' - describe('Login Page', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.intercept('POST', '/kauth/api/v2/logout', { - statusCode: 200, + cy.mockStylesheetFont() + cy.intercept('POST', '**/developer/logout', { + statusCode: 204, body: {}, delay: 300 }).as('userLogout') @@ -65,7 +64,7 @@ describe('Login Page', () => { data: [] }, delay: 300 - }).as('getServices') + }).as('getProducts') cy.mockGetUserInfo() @@ -94,7 +93,7 @@ describe('Login Page', () => { data: [] }, delay: 300 - }).as('getServices') + }).as('getProducts') cy.visit('/', { useOriginalFn: true }) cy.location('pathname').should('equal', '/login') @@ -112,47 +111,35 @@ describe('Login Page', () => { }) it('is denied access and shows error message on bad credentials', () => { - cy.intercept('POST', '/kauth/api/v1/developer-authenticate', { - statusCode: 401, + cy.intercept('POST', '**/developer/authenticate', { + statusCode: 400, body: { - data: { - errors: [ - { - status: '401', - code: '1003', - title: 'Invalid username or password', - detail: 'you have entered an invalid username or password (#1003)' - } - ] - } + status: 404, + title: 'Not Found', + detail: 'The requested developer was not found' }, delay: 300 }).as('userAuthenticate') cy.visit('/login', { useOriginalFn: true }) cy.location('pathname').should('equal', '/login') - cy.get('input[id=email]').type('uh') + cy.get('input[id=email]').type('uh@email.com') cy.wait(500) cy.get('input[id=password]').type('not-valid{enter}') cy.wait('@userAuthenticate').then(() => { cy.url().should('include', '/login') cy.get('[data-testid="kong-auth-error-message"]') - .should('contain', 'Incorrect username or password. Please try again.') + .should('contain', 'The requested developer was not found') }) }) it('is denied access and shows error message when developer not yet allowed access', () => { - cy.intercept('POST', '/kauth/api/v1/developer-authenticate', { + cy.intercept('POST', '**/developer/authenticate', { statusCode: 401, body: { - errors: [ - { - status: '401', - code: '1007', - title: 'Account is disabled', - detail: 'user account is disabled (#1007)' - } - ] + status: 401, + title: "Developer is disabled", + detail: "Your account is disabled." }, delay: 300 }).as('userAuthenticate') @@ -170,8 +157,8 @@ describe('Login Page', () => { }) it('confirms email and resets password when developer status is pending', () => { - cy.intercept('PATCH', '/kauth/api/v1/developer-email-verifications', { - statusCode: 200, + cy.intercept('POST', '**/developer/verify-email', { + statusCode: 202, body: { email: 'email', resetToken: 'token' @@ -179,11 +166,8 @@ describe('Login Page', () => { delay: 300 }).as('verifyEmailToken') - cy.intercept('PATCH', '/kauth/api/v1/developer-password-resets', { - statusCode: 200, - body: { - email: 'testing123@gmail.com' - }, + cy.intercept('POST', '**/developer/reset-password', { + statusCode: 204, delay: 300 }).as('passwordReset') cy.visit('/login?email=testing12302%40gmail.com&token=123', { useOriginalFn: true }) @@ -209,16 +193,13 @@ describe('Login Page', () => { }) it('throws 500 error when confirmation token has been used', () => { - cy.intercept('PATCH', '/kauth/api/v1/developer-email-verifications', { + cy.intercept('POST', '**/developer/verify-email', { statusCode: 500, body: { - errors: [ - { - status: '500', - title: 'Internal Server Error', - detail: 'invalid status update request' - } - ] + "status": 500, + "title": "Internal", + "instance": "konnect:trace:1158228726469534496", + "detail": "An internal failure occurred" }, delay: 300 }).as('verifyEmailToken') @@ -228,7 +209,7 @@ describe('Login Page', () => { // returns to the login page cy.location('pathname').should('equal', '/login') cy.get('[data-testid="kong-auth-error-message"]') - .should('contain', 'Invalid status update request') + .should('contain', 'An internal failure occurred') cy.get('input[id=email]').should('exist') }) @@ -254,7 +235,7 @@ describe('Login Page', () => { }) it('routes to intended page after SSO login', () => { - cy.intercept('**/kauth/api/v1/developer-authenticate/123*', (req) => { + cy.intercept('**/developer/authenticate/sso*', (req) => { req.redirect(`${Cypress.config().baseUrl}?loginSuccess=true`, 301) }) @@ -265,14 +246,15 @@ describe('Login Page', () => { cy.location('pathname').should('equal', '/login') cy.get('[data-testid="auth-form"]').should('be.visible') cy.get('[data-testid="kong-auth-login-sso"]').should('be.visible').click() - cy.mockServicePackage('*') - cy.mockServicePackageDocumentTree() + cy.mockProduct('*') + cy.mockProductDocumentTree() cy.mockProductVersionSpec() - cy.mockServiceOperations() + cy.mockProductOperations() cy.location('pathname').should('equal', '/spec/test') }) it('does not hang on loading when loginSuccess provided by user', () => { + cy.mockDeveloperRefresh() cy.intercept('GET', '**/api/v2/developer/me', { statusCode: 401, body: { diff --git a/cypress/e2e/specs/not_found.spec.ts b/cypress/e2e/specs/not_found.spec.ts index 1f8d56ca..3d763861 100644 --- a/cypress/e2e/specs/not_found.spec.ts +++ b/cypress/e2e/specs/not_found.spec.ts @@ -1,6 +1,7 @@ describe('Not Found Page', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockStylesheetFont() }) describe('not found spec', () => { @@ -12,9 +13,10 @@ describe('Not Found Page', () => { }) it('allows able to move to home using button available on 404 page', () => { + cy.mockProductsCatalog() cy.visit('/oooooooooo') cy.get('[data-testid="go-home"]').click() - cy.get('.services-welcome').should('exist') + cy.get('.products-welcome').should('exist') }) }) }) diff --git a/cypress/e2e/specs/portal_auth.spec.ts b/cypress/e2e/specs/portal_auth.spec.ts index 4eb3cc92..2bf717fc 100644 --- a/cypress/e2e/specs/portal_auth.spec.ts +++ b/cypress/e2e/specs/portal_auth.spec.ts @@ -1,8 +1,6 @@ -import { v4 as uuidv4 } from 'uuid' - -const servicePackageId = 'a5afb115-025e-4da1-a013-bf05b326e0a51' -const serviceVersionId = '1afac832-5b2a-474c-a56d-c241364f41cf' -const applicationId = uuidv4() +const productId = crypto.randomUUID() +const productVersionId = crypto.randomUUID() +const applicationId = crypto.randomUUID() const matrix = { isNotPublic: { @@ -12,8 +10,8 @@ const matrix = { '/application/:applicationId', '/application/create', '/my-apps', - '/spec/:servicePackageId', - '/spec/:servicePackageId/:serviceVersionId' + '/spec/:productId', + '/spec/:productId/:productVersionId' ], viewable: [ '/forgot-password', @@ -30,8 +28,8 @@ const matrix = { '/my-apps', '/forgot-password', '/reset-password', - '/spec/:servicePackageId', - '/spec/:servicePackageId/:serviceVersionId' + '/spec/:productId', + '/spec/:productId/:productVersionId' ], redirectToSlash: [ '/login', @@ -43,8 +41,8 @@ const matrix = { authenticated: { viewable: [ '/', - '/spec/:servicePackageId', - '/spec/:servicePackageId/:serviceVersionId' + '/spec/:productId', + '/spec/:productId/:productVersionId' ], redirectToSlash: [ '/application/:applicationId', @@ -59,8 +57,8 @@ const matrix = { unauthenticated: { viewable: [ '/', - '/spec/:servicePackageId', - '/spec/:servicePackageId/:serviceVersionId' + '/spec/:productId', + '/spec/:productId/:productVersionId' ], redirectToSlash: [ '/application/:applicationId', @@ -76,8 +74,8 @@ const matrix = { } const replaceRouteValues = route => route - .replace(/:servicePackageId/g, servicePackageId) - .replace(/:serviceVersionId/g, serviceVersionId) + .replace(/:productId/g, productId) + .replace(/:productVersionId/g, productVersionId) .replace(/:applicationId/g, applicationId) // when true it means that it tried to access without cookie set @@ -88,9 +86,14 @@ const aliasVisitAndWait = (route, useOriginalFn = true) => { } describe('Portal Auth', () => { + beforeEach(() => { + cy.mockStylesheetFont() + }) + describe('Private Portal - Unauthenticated', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockDeveloperLogout() }) matrix.isNotPublic.unauthenticated.redirectToLogin.forEach((route) => { @@ -120,6 +123,9 @@ describe('Portal Auth', () => { describe('Private Portal - Authenticated', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockProductsCatalog() + cy.mockStylesheetFont() + cy.mockStylesheetCss() }) matrix.isNotPublic.authenticated.viewable.forEach((route) => { @@ -148,6 +154,11 @@ describe('Portal Auth', () => { describe('Public Portal - Authenticated', () => { beforeEach(() => { cy.mockPublicPortal() + cy.mockProductsCatalog() + cy.mockStylesheetFont() + cy.mockStylesheetCss() + cy.mockAppearance() + cy.mockApplications() }) matrix.isPublic.unauthenticated.viewable.forEach((route) => { @@ -176,6 +187,10 @@ describe('Portal Auth', () => { describe('Public Portal - Unauthenticated', () => { beforeEach(() => { cy.mockPublicPortal() + cy.mockProductsCatalog() + cy.mockStylesheetFont() + cy.mockStylesheetCss() + cy.mockAppearance() }) matrix.isPublic.unauthenticated.viewable.forEach((route) => { diff --git a/cypress/e2e/specs/register.spec.ts b/cypress/e2e/specs/register.spec.ts index 1af8ca38..68a97621 100644 --- a/cypress/e2e/specs/register.spec.ts +++ b/cypress/e2e/specs/register.spec.ts @@ -1,6 +1,8 @@ describe('Register Page', () => { beforeEach(() => { cy.mockPrivatePortal() + cy.mockStylesheetFont() + cy.mockDeveloperLogout() }) describe('register', () => { diff --git a/cypress/e2e/specs/reset_password.spec.ts b/cypress/e2e/specs/reset_password.spec.ts index 3712631e..666bce61 100644 --- a/cypress/e2e/specs/reset_password.spec.ts +++ b/cypress/e2e/specs/reset_password.spec.ts @@ -1,15 +1,12 @@ - describe('Reset Password Page', () => { beforeEach(() => { cy.mockPrivatePortal() cy.mockSuccessfulPasswordReset() + cy.mockStylesheetFont() }) it('Sends token to backend that developer can get from email and resets password', () => { - cy.intercept('PATCH', '/kauth/api/v1/developer-password-resets', { - statusCode: 200, - body: { - email: 'testing123@email.com' - }, + cy.intercept('POST', '**/developer/reset-password', { + statusCode: 204, delay: 300 }).as('resetPassword') @@ -44,21 +41,15 @@ describe('Reset Password Page', () => { }) }) it('Errors out if reset token is invalid', () => { - cy.intercept('PATCH', '/kauth/api/v1/developer-password-resets', { - statusCode: 400, + cy.intercept('POST', '**/developer/reset-password', { + statusCode: 500, body: - { - errors: [ - { - status: '400', - title: 'Invalid Token', - detail: 'The password reset token is invalid', - source: { - pointer: '/token' - } - } - ] - }, + { + "status": 500, + "title": "Internal", + "instance": "konnect:trace:1115722991246784904", + "detail": "An internal failure occurred" + }, delay: 300 }).as('resetPassword') @@ -84,7 +75,7 @@ describe('Reset Password Page', () => { cy.wait('@resetPassword').then(() => { // Stays on the page as token is invalid - cy.get('[data-testid="kong-auth-error-message"]').should('contain', 'The password reset token is invalid') + cy.get('[data-testid="kong-auth-error-message"]').should('contain', 'An internal failure occurred') cy.location('pathname').should('equal', '/reset-password') }) }) diff --git a/cypress/e2e/specs/spec_renderer.spec.ts b/cypress/e2e/specs/spec_renderer.spec.ts index a0920353..2f410406 100644 --- a/cypress/e2e/specs/spec_renderer.spec.ts +++ b/cypress/e2e/specs/spec_renderer.spec.ts @@ -1,20 +1,24 @@ -import { product as servicePackage, versions } from '../fixtures/consts' +import { product, versions } from '../fixtures/consts' import petstoreJson from '../fixtures/oas_specs/petstoreJson.json' import petstoreJson3 from '../fixtures/oas_specs/petstoreJson3.0.json' describe('Spec Renderer Page', () => { + beforeEach(() => { + cy.mockStylesheetFont() + }) describe('Spec Render Yaml', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.mockServiceDocument() - cy.mockServicePackage() - cy.mockServicePackageDocumentTree() - cy.mockServiceOperations() + cy.mockProductDocument() + cy.mockProductsCatalog() + cy.mockProduct() + cy.mockProductDocumentTree() + cy.mockProductOperations() cy.mockProductVersionSpec() }) it('can return to Catalog from spec details via breadcrumb', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) @@ -24,9 +28,9 @@ describe('Spec Renderer Page', () => { }) it('renders page', () => { - cy.mockServiceVersionApplicationRegistration(versions[0]) + cy.mockProductVersionApplicationRegistration(versions[0]) - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.version-select-dropdown').should('contain', 'v1-beta') // loads swagger title @@ -36,7 +40,7 @@ describe('Spec Renderer Page', () => { }) it('raw button', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) // displays view spec modal .get('kong-swagger-ui').shadow().find('.actions button.btn-outline').click() @@ -57,7 +61,7 @@ describe('Spec Renderer Page', () => { }) it('loads page title and url is correct', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.get('.info') // here to make sure we wait for load cy.title().should('eq', 'barAPI - v1-beta | Developer Portal') }) @@ -66,15 +70,15 @@ describe('Spec Renderer Page', () => { describe('Spec Render Json', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.mockServiceDocument() - cy.mockServicePackage() - cy.mockServicePackageDocumentTree() - cy.mockServiceOperations() + cy.mockProductDocument() + cy.mockProduct() + cy.mockProductDocumentTree() + cy.mockProductOperations() cy.mockProductVersionSpec() }) it('renders page', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) // loads version text .get('.version-select-dropdown').should('contain', 'v1-beta') @@ -85,7 +89,7 @@ describe('Spec Renderer Page', () => { }) it('raw button', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) // displays view spec modal .get('kong-swagger-ui').shadow().find('.actions button.btn-outline').click() @@ -109,15 +113,15 @@ describe('Spec Renderer Page', () => { describe('Spec Render OAS3 ', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.mockServiceDocument('*', '*', { body: petstoreJson3 }) - cy.mockServicePackage() - cy.mockServicePackageDocumentTree() - cy.mockServiceOperations() + cy.mockProductDocument('*', '*', { body: petstoreJson3 }) + cy.mockProduct() + cy.mockProductDocumentTree() + cy.mockProductOperations() cy.mockProductVersionSpec() }) it('renders page', () => { - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) // loads version text .get('.version-select-dropdown').should('contain', 'v1-beta') @@ -132,13 +136,22 @@ describe('Spec Renderer Page', () => { }) describe('Multiple Versions', () => { + beforeEach(() => { + cy.mockPrivatePortal() + cy.mockProductDocument() + cy.mockProductsCatalog() + cy.mockProduct() + cy.mockProductDocumentTree() + cy.mockProductOperations() + cy.mockProductVersionSpec() + }) const weirdVersionName = 'weird <> % $ `' const v2BetaVersion = { created_at: '2022-03-24T14:52:46.323Z', updated_at: '2022-03-27T14:52:46.323Z', id: '2afac832-5b2a-474c-a56d-c241364f41cf', - version: 'v2-beta', + name: 'v2-beta', publish_status: 'published', registration_configs: [], deprecated: false @@ -148,13 +161,13 @@ describe('Spec Renderer Page', () => { created_at: '2022-03-24T13:52:46.323Z', updated_at: '2022-03-24T13:52:46.323Z', id: '2afac832-4b2a-474c-a56d-c241364f41cf', - version: weirdVersionName, + name: weirdVersionName, publish_status: 'published', registration_configs: [], deprecated: false } - const servicePackageBody = { - ...servicePackage + const productBody = { + ...product } const mockedVersions = [ @@ -163,7 +176,7 @@ describe('Spec Renderer Page', () => { v2BetaVersion ] - const serviceDocumentPetttstorrreeeBody = { + const productDocumentPetttstorrreeeBody = { ...petstoreJson, info: { ...petstoreJson.info, @@ -171,7 +184,7 @@ describe('Spec Renderer Page', () => { description: 'This is petstore json, not to be confused with petstore yaml' } } - const serviceDocumentWeirdPetStoreBody = { + const productDocumentWeirdPetStoreBody = { ...petstoreJson, info: { ...petstoreJson.info, @@ -182,18 +195,18 @@ describe('Spec Renderer Page', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.mockServiceVersionApplicationRegistration(versions[0]) - cy.mockServiceOperations() - cy.mockGetServicePackageDocumentTree() + cy.mockProductVersionApplicationRegistration(versions[0]) + cy.mockProductOperations() + cy.mockGetProductDocumentTree() cy.mockProductVersionSpec() }) it('loads a new spec when selected from the dropdown', () => { - cy.mockServicePackage(servicePackage.id, servicePackageBody, mockedVersions) - cy.mockServiceDocument(servicePackage.id, v2BetaVersion.id, { - body: serviceDocumentPetttstorrreeeBody + cy.mockProduct(product.id, productBody, mockedVersions) + cy.mockProductDocument(product.id, v2BetaVersion.id, { + body: productDocumentPetttstorrreeeBody }) - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) cy.get('.info h2').should('contain', 'Swagger Petstore') @@ -201,7 +214,7 @@ describe('Spec Renderer Page', () => { .title().should('eq', 'barAPI - v1-beta | Developer Portal') .url().should('include', versions[0].id) - cy.mockProductVersionSpec('*', '*', JSON.stringify(serviceDocumentPetttstorrreeeBody)) + cy.mockProductVersionSpec('*', '*', JSON.stringify(productDocumentPetttstorrreeeBody)) cy.get('.version-select-dropdown').click() .get('.version-select-dropdown').contains('v2-beta').click() @@ -212,13 +225,13 @@ describe('Spec Renderer Page', () => { .title().should('eq', 'barAPI - v2-beta | Developer Portal') .url().should('include', v2BetaVersion.id) - cy.mockServicePackage(servicePackage.id, servicePackageBody, mockedVersions) + cy.mockProduct(product.id, productBody, mockedVersions) cy.mockProductVersionSpec() cy.go('back') // back button works - cy.mockServiceOperations() - cy.mockServiceDocument() - cy.mockGetServicePackageDocumentTree() + cy.mockProductOperations() + cy.mockProductDocument() + cy.mockGetProductDocumentTree() .wait(1000) cy.get('.info h2').should('contain', 'Swagger Petstore') @@ -226,18 +239,18 @@ describe('Spec Renderer Page', () => { }) it('supports navigating to version using name', () => { - cy.mockServicePackage(servicePackage.id, servicePackageBody, mockedVersions) + cy.mockProduct(product.id, productBody, mockedVersions) - cy.visit(`/spec/${servicePackage.id}/v1-beta`) + cy.visit(`/spec/${product.id}/v1-beta`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Swagger Petstore') .get('.info').contains('This comes from the spec') .title().should('eq', 'barAPI - v1-beta | Developer Portal') - cy.mockProductVersionSpec('*', '*', JSON.stringify(serviceDocumentPetttstorrreeeBody)) + cy.mockProductVersionSpec('*', '*', JSON.stringify(productDocumentPetttstorrreeeBody)) - cy.visit(`/spec/${servicePackage.id}/v2-beta`) + cy.visit(`/spec/${product.id}/v2-beta`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Petttstorrreee') @@ -246,18 +259,18 @@ describe('Spec Renderer Page', () => { }) it('supports navigating to version using uuid', () => { - cy.mockServicePackage(servicePackage.id, servicePackageBody, mockedVersions) + cy.mockProduct(product.id, productBody, mockedVersions) - cy.visit(`/spec/${servicePackage.id}/${versions[0].id}`) + cy.visit(`/spec/${product.id}/${versions[0].id}`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Swagger Petstore') .get('.info').contains('This comes from the spec') .title().should('eq', 'barAPI - v1-beta | Developer Portal') - cy.mockProductVersionSpec('*', '*', JSON.stringify(serviceDocumentPetttstorrreeeBody)) + cy.mockProductVersionSpec('*', '*', JSON.stringify(productDocumentPetttstorrreeeBody)) - cy.visit(`/spec/${servicePackage.id}/${v2BetaVersion.id}`) + cy.visit(`/spec/${product.id}/${v2BetaVersion.id}`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Petttstorrreee') @@ -266,19 +279,19 @@ describe('Spec Renderer Page', () => { }) it('double UriComponent encodes the version', () => { - cy.mockServiceVersionApplicationRegistration(weirdVersion) - cy.mockServiceOperations() - cy.mockGetServicePackageDocumentTree() - cy.mockServicePackage(servicePackage.id, servicePackageBody, mockedVersions) + cy.mockProductVersionApplicationRegistration(weirdVersion) + cy.mockProductOperations() + cy.mockGetProductDocumentTree() + cy.mockProduct(product.id, productBody, mockedVersions) - cy.mockProductVersionSpec('*', '*', JSON.stringify(serviceDocumentWeirdPetStoreBody)) + cy.mockProductVersionSpec('*', '*', JSON.stringify(productDocumentWeirdPetStoreBody)) - cy.visit(`/spec/${servicePackage.id}/${encodeURIComponent(encodeURIComponent(weirdVersionName))}`) + cy.visit(`/spec/${product.id}/${encodeURIComponent(encodeURIComponent(weirdVersionName))}`) .get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'weird petstore') .title().should('eq', `barAPI - ${weirdVersionName} | Developer Portal`) - cy.mockServicePackage(servicePackage.id, servicePackageBody) + cy.mockProduct(product.id, productBody) cy.mockProductVersionSpec() @@ -288,9 +301,9 @@ describe('Spec Renderer Page', () => { .get('.info h2').should('contain', 'Swagger Petstore') .url().should('include', versions[0].id) - cy.mockServicePackage(servicePackage.id, servicePackageBody) + cy.mockProduct(product.id, productBody) - cy.mockProductVersionSpec('*', '*', JSON.stringify(serviceDocumentWeirdPetStoreBody)) + cy.mockProductVersionSpec('*', '*', JSON.stringify(productDocumentWeirdPetStoreBody)) cy.get('.version-select-dropdown').click() .get('.version-select-dropdown').contains(weirdVersionName).click() @@ -304,10 +317,12 @@ describe('Spec Renderer Page', () => { describe('Spec Render permissions', () => { beforeEach(() => { cy.mockPrivatePortal() - cy.mockServiceDocument() - cy.mockServicePackage() + cy.mockProductDocument() + cy.mockProduct() cy.mockProductVersionSpec() - cy.mockServiceVersionApplicationRegistration(versions[0]) + cy.mockProductVersionApplicationRegistration(versions[0]) + cy.mockProductDocumentTree() + cy.mockProductOperations() }) it('redirects to 403 page when developer does not have permissions to see the spec', () => { @@ -324,7 +339,7 @@ describe('Spec Renderer Page', () => { delay: 300 }).as('getPermissions') - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.wait('@getPermissions') @@ -348,7 +363,7 @@ describe('Spec Renderer Page', () => { delay: 300 }).as('getPermissions') - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.wait('@getPermissions') @@ -365,7 +380,7 @@ describe('Spec Renderer Page', () => { cy.intercept('get', 'api/v2/portals/*/developers/me/permissions', cy.spy().as('apiNotCalled')) - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Swagger Petstore') @@ -379,10 +394,15 @@ describe('Spec Renderer Page', () => { describe('Spec Render permissions public', () => { beforeEach(() => { cy.mockPublicPortal() - cy.mockServiceDocument() - cy.mockServicePackage() + cy.mockProductDocument() + cy.mockProduct() cy.mockProductVersionSpec() - cy.mockServiceVersionApplicationRegistration(versions[0]) + cy.mockProductVersionApplicationRegistration(versions[0]) + cy.mockProductDocumentTree() + cy.mockProductOperations() + cy.mockStylesheetFont() + cy.mockStylesheetCss() + cy.mockAppearance() }) it('allows seeing spec when portal is public and rbac enabled, does not call developers/me/permissions', () => { @@ -392,7 +412,7 @@ describe('Spec Renderer Page', () => { cy.intercept('get', 'api/v2/portals/*/developers/me/permissions', cy.spy().as('apiNotCalled')) - cy.visit(`/spec/${servicePackage.id}`) + cy.visit(`/spec/${product.id}`) cy.get('[data-testid="kong-public-ui-spec-details-swagger"]', { timeout: 12000 }) .get('.info h2').should('contain', 'Swagger Petstore') diff --git a/cypress/e2e/specs/themeing.spec.ts b/cypress/e2e/specs/themeing.spec.ts index bfc9621e..d39175e1 100644 --- a/cypress/e2e/specs/themeing.spec.ts +++ b/cypress/e2e/specs/themeing.spec.ts @@ -7,6 +7,10 @@ beforeEach(() => { }) describe('loads color theme variables', () => { + beforeEach(() => { + cy.mockStylesheetFont() + cy.mockAppearance() + }) it('loads mint_rocket theme', () => { cy.mockStylesheetCss('mint_rocket') cy.visit('/') @@ -49,6 +53,8 @@ describe('loads color theme variables', () => { describe('fonts', () => { it('loads default fonts', () => { cy.mockStylesheetFont() + cy.mockStylesheetCss() + cy.mockAppearance() cy.visit('/') cy.get('#site-header') cy.get('body').should('have.css', 'font').should('contain', DEFAULT_FONTS.base) @@ -66,17 +72,21 @@ describe('fonts', () => { }) describe('custom Catalog', () => { + beforeEach(() => { + cy.mockStylesheetFont() + cy.mockStylesheetCss() + }) it('loads default values', () => { cy.mockPublicPortal() cy.mockAppearance() cy.visit('/') cy.get('#site-header') - cy.get('.services-welcome').should('contain', 'Welcome to our API Portal!') - cy.get('.services-title').should('contain', 'Start building and innovating with our APIs') - cy.get('.services-top-section').should('have.css', 'background-image').and('not.match', /catalog_cover/) + cy.get('.products-welcome').should('contain', 'Welcome to our API Portal!') + cy.get('.products-title').should('contain', 'Start building and innovating with our APIs') + cy.get('.products-top-section').should('have.css', 'background-image').and('not.match', /catalog_cover/) }) it('loads custom values', () => { - cy.readFile('cypress/e2e/kong-logo.png', 'base64').then(b => { + cy.readFile('cypress/e2e/fixtures/images/kong-logo.png', 'base64').then(b => { cy.mockAppearance({ variables: { catalog: { @@ -93,9 +103,9 @@ describe('custom Catalog', () => { cy.visit('/') cy.wait('@getAppearance') cy.get('#site-header') - cy.get('.services-welcome').should('contain', 'Hey Joe') - cy.get('.services-title').should('contain', "where you goin' with that gun in your hand?") - cy.get('.services-top-section').should('have.css', 'background-image').and('match', /catalog-cover/) + cy.get('.products-welcome').should('contain', 'Hey Joe') + cy.get('.products-title').should('contain', "where you goin' with that gun in your hand?") + cy.get('.products-top-section').should('have.css', 'background-image').and('match', /catalog-cover/) }) }) }) diff --git a/cypress/e2e/support/index.ts b/cypress/e2e/support/index.ts index a1553c21..04e08ee7 100644 --- a/cypress/e2e/support/index.ts +++ b/cypress/e2e/support/index.ts @@ -1,6 +1,8 @@ +/* eslint-disable no-console */ // Import commands.js using ES2015 syntax: -import { GetApplicationResponse, GetRegistrationResponse, PortalAppearance, PortalContext, Product, ProductCatalogIndexSource, ProductVersion, ProductVersionSpecOperationsOperationsInner } from '@kong/sdk-portal-js' +import { GetApplicationResponse, GetRegistrationResponse, ListCredentialsResponseDataInner, PortalAppearance, PortalContext, Product, ProductCatalogIndexSource, ProductVersion, ProductVersionSpecOperationsOperationsInner } from '@kong/sdk-portal-js' import './mock-commands' +import { SinonStub } from 'cypress/types/sinon' // from https://docs.cypress.io/guides/tooling/typescript-support declare global { @@ -18,26 +20,55 @@ declare global { mockSuccessfulDeveloperAuth(): Chainable> mockSuccessfulPasswordReset(): Chainable> mockGetUserInfo(): Chainable> - mockServiceDocument(productId?:string, productVersionId?:string, options?: Partial & {body: any}): Chainable> - mockServicePackageDocumentTree(productId?: string, options?: Partial & {body: any}): Chainable> - mockServicePackageApiDocument(productId?: string, options?: Partial & {body: any}): Chainable> - mockServicePackage(productId?: string, mockServicePackage?: Product, mockVersions?: ProductVersion[]): Chainable> + mockProductDocument(productId?:string, productVersionId?:string, options?: Partial & {body: any}): Chainable> + mockProductDocumentTree(productId?: string, options?: Partial & {body: any}): Chainable> + mockProductApiDocument(productId?: string, options?: Partial & {body: any}): Chainable> + mockProduct(productId?: string, mockProduct?: Product, mockVersions?: ProductVersion[]): Chainable> mockApplications(searchResults?: Array, totalCount?: number, pageSize?: number, pageNumber?: number): Chainable> + mockApplicationWithCredAndReg(data: GetApplicationResponse, credentials?: ListCredentialsResponseDataInner[], registrations?: Array): Chainable>, + mockContextualAnalytics(): Chainable> mockRegistrations(applicationId?: string, registrations?: Array, totalCount?: number): Chainable> - mockServiceVersionApplicationRegistration(value:any): Chainable> + mockProductVersionApplicationRegistration(value:any): Chainable> mockProductsCatalog(count?: number, overrides?: Partial[], pageNum?:number, pageSize?:number): Chainable> - mockGetServicePackageDocumentBySlug(servicePckageId: string, slug:string, options?:Partial & {document?:any, revision?: any}): Chainable> - mockGetServicePackageDocuments(productId:string): Chainable> - mockGetServicePackageDocumentTree(productId?:string): Chainable> + mockGetProductDocumentBySlug(servicePckageId: string, slug:string, options?:Partial & {document?:any, revision?: any}): Chainable> + mockGetProductDocuments(productId:string): Chainable> + mockGetProductDocumentTree(productId?:string): Chainable> createNewApplication(app: GetApplicationResponse, productId?: string, versions?: any[], options?: Partial): Chainable - mockServiceOperations(productId?:string, versionId?:string, operations?: ProductVersionSpecOperationsOperationsInner[]): Chainable> + mockProductOperations(productId?:string, versionId?:string, operations?: ProductVersionSpecOperationsOperationsInner[]): Chainable> mockProductVersionSpec(productId?:string, versionId?:string, content?: string): Chainable> mockStylesheetFont(fonts?: {[key:string]:string}): Chainable> mockStylesheetCss(themeName?: string, fonts?: {[key:string]:string}): Chainable> mockAppearance(appearance?: PortalAppearance): Chainable> + mockLogo(): Chainable> + mockCatalogCover(): Chainable> + mockLaunchDarklyFlags(flags: Array<{name:string, value:boolean}>): Chainable> + mockDeveloperRefresh(): Chainable> + mockDeveloperLogout(): Chainable> } } } // Import commands.js using ES2015 syntax: require('cypress-terminal-report/src/installLogsCollector')() + +beforeEach(() => { + const API_URL = Cypress.env('VITE_PORTAL_API_URL') + const notMockedAPIRequests = cy.stub().as('notMockedAPIRequests') + const notMockedLDRequests = cy.stub().as('unmockedLaunchDarklyRequests') + + // mock all API requests + cy.intercept(`**${API_URL}**`, notMockedAPIRequests) + + // mock all launchdarkly requests + cy.intercept('https://*.launchdarkly.com/**', notMockedLDRequests) +}) + +afterEach(() => { + cy.get('@notMockedAPIRequests') + .then(stub => cy.wrap(stub.getCalls().map(call => call.args[0].url).join(', '))) + .then(urls => console.info({ message: 'Unmocked API requests', urls })) + + cy.get('@unmockedLaunchDarklyRequests') + .then(stub => cy.wrap(stub.getCalls().map(call => call.args[0].url).join(', '))) + .then(urls => console.info({ message: 'Unmocked LD requests', urls })) +}) diff --git a/cypress/e2e/support/mock-commands.ts b/cypress/e2e/support/mock-commands.ts index e7f26796..6a9a7c99 100644 --- a/cypress/e2e/support/mock-commands.ts +++ b/cypress/e2e/support/mock-commands.ts @@ -1,14 +1,29 @@ -import { v4 as uuidv4 } from 'uuid' import petstoreJson from '../fixtures/oas_specs/petstoreJson.json' import petstoreJson30 from '../fixtures/oas_specs/petstoreJson3.0.json' import { generateProducts } from './utils/generateProducts' import { generateDocuments } from './utils/generateDocuments' -import { defaultContext, product as servicePackage, versions } from '../fixtures/consts' +import { defaultContext, product, versions } from '../fixtures/consts' import document from '../fixtures/dochub_mocks/document.json' import documentTreeJson from '../fixtures/dochub_mocks/documentTree.json' import apiDocumentationJson from '../fixtures/dochub_mocks/parentApiDocumentation.json' import petstoreOperationsV2 from '../fixtures/v2/petstoreOperations.json' -import { ListApplicationsResponse, ListDocumentsTree, PortalAppearance, PortalContext, Product, ProductDocument, ProductDocumentRaw, ProductVersionListPage, ProductVersionSpec, ProductVersionSpecOperations, ProductVersionSpecOperationsOperationsInner, SearchResults } from '@kong/sdk-portal-js' +import { + GetApplicationResponse, + ListApplicationsResponse, + ListCredentialsResponse, + ListDocumentsTree, + ListRegistrationsResponse, + PortalAppearance, + PortalContext, + Product, + ProductDocument, + ProductDocumentRaw, + ProductVersionListPage, + ProductVersionSpecDocument, + ProductVersionSpecOperations, + ProductVersionSpecOperationsOperationsInner, + SearchResults +} from '@kong/sdk-portal-js' import { THEMES } from '../fixtures/theme.constant' Cypress.Commands.add('mockStylesheetCss', (theme = 'mint_rocket', fonts = { @@ -53,6 +68,8 @@ Cypress.Commands.add('mockAppearance', (appearance = {}) => { } } } + cy.mockLogo() + cy.mockCatalogCover() cy.intercept('GET', '**/api/v2/portal/appearance', { statusCode: 200, @@ -63,6 +80,18 @@ Cypress.Commands.add('mockAppearance', (appearance = {}) => { }).as('getAppearance') }) +Cypress.Commands.add('mockCatalogCover', () => { + cy.intercept('GET', '**/api/v2/portal/catalog-cover', { + fixture: 'images/kong-logo.png' + }).as('getCatalogCover') +}) + +Cypress.Commands.add('mockLogo', () => { + cy.intercept('GET', '**/api/v2/portal/logo', { + fixture: 'images/kong-logo.png' + }).as('getLogo') +}) + Cypress.Commands.add('mockStylesheetFont', (fonts = { base: 'Roboto', headings: 'Lato', @@ -124,7 +153,7 @@ Cypress.Commands.add('mockDcrPortal', () => { const portalContextResponse: PortalContext = { ...defaultContext, - dcr_provider_ids: [uuidv4()] + dcr_provider_ids: [crypto.randomUUID()] } return cy.intercept('GET', '**/api/v2/portal', { @@ -148,12 +177,19 @@ Cypress.Commands.add('mockPublicPortal', () => { }) Cypress.Commands.add('mockSuccessfulDeveloperAuth', () => { - return cy.intercept('POST', '**/kauth/api/v1/developer-authenticate', { - statusCode: 200, + return cy.intercept('POST', '**/developer/authenticate', { + statusCode: 204, body: {}, delay: 300 }).as('userAuthenticate') }) +Cypress.Commands.add('mockDeveloperRefresh', () => { + return cy.intercept('POST', '**/developer/refresh', { + statusCode: 204, + body: {}, + delay: 300 + }).as('developerRefresh') +}) Cypress.Commands.add('mockSuccessfulPasswordReset', () => { return cy.intercept('POST', '**/api/v2/developer/forgot-password', { @@ -162,6 +198,13 @@ Cypress.Commands.add('mockSuccessfulPasswordReset', () => { }).as('sendPasswordReset') }) +Cypress.Commands.add('mockDeveloperLogout', () => { + return cy.intercept('POST', '**/api/v2/developer/logout', { + statusCode: 200, + delay: 300 + }).as('developerLogout') +}) + Cypress.Commands.add('mockGetUserInfo', () => { return cy.intercept('GET', '**/api/v2/developer/me', { statusCode: 200, @@ -176,7 +219,7 @@ Cypress.Commands.add('mockGetUserInfo', () => { }).as('getUserInfo') }) -Cypress.Commands.add('mockServiceDocument', (productId = '*', documentId = '*', options = { body: petstoreJson }) => { +Cypress.Commands.add('mockProductDocument', (productId = '*', documentId = '*', options = { body: petstoreJson }) => { const documentTreeResponse: ProductDocumentRaw = { content: JSON.stringify(options.body), id: documentId, @@ -192,7 +235,7 @@ Cypress.Commands.add('mockServiceDocument', (productId = '*', documentId = '*', }).as('getMockedServiceDocument') }) -Cypress.Commands.add('mockServicePackageDocumentTree', (productId = '*', options = { body: documentTreeJson }) => { +Cypress.Commands.add('mockProductDocumentTree', (productId = '*', options = { body: documentTreeJson }) => { const documentTreeResponse: ListDocumentsTree = { data: options.body, meta: { @@ -208,20 +251,20 @@ Cypress.Commands.add('mockServicePackageDocumentTree', (productId = '*', options statusCode: 200, delay: 100, body: documentTreeResponse - }).as('getMockServicePackageDocumentTree') + }).as('getMockProductDocumentTree') }) -Cypress.Commands.add('mockServicePackageApiDocument', (productId = '*', options = { body: apiDocumentationJson }) => { +Cypress.Commands.add('mockProductApiDocument', (productId = '*', options = { body: apiDocumentationJson }) => { const productDocumentResponse: ProductDocument = options.body return cy.intercept('GET', `**/api/v2/products/${productId}/documents/${productDocumentResponse.slug}`, { statusCode: 200, delay: 100, body: productDocumentResponse - }).as('getMockServicePackageApiDocument') + }).as('getMockProductApiDocument') }) -Cypress.Commands.add('mockServicePackage', (productId = '*', mockServicePackage = servicePackage, mockVersions = versions) => { +Cypress.Commands.add('mockProduct', (productId = '*', mockProduct = product, mockVersions = versions) => { const versionsResponse: ProductVersionListPage = { data: mockVersions, meta: { @@ -238,14 +281,14 @@ Cypress.Commands.add('mockServicePackage', (productId = '*', mockServicePackage }) const productResponse: Product = { - ...mockServicePackage + ...mockProduct } return cy.intercept('GET', `**/api/v2/products/${productId}`, { statusCode: 200, delay: 100, body: productResponse - }).as('getServicePackage') + }).as('getProduct') }) Cypress.Commands.overwrite('visit', (originalFn, ...options) => { @@ -304,22 +347,76 @@ Cypress.Commands.add('mockRegistrations', (applicationId = '*', registrations = }).as('getRegistrations') }) -Cypress.Commands.add('mockServiceVersionApplicationRegistration', (version, config = {}) => { +Cypress.Commands.add('mockApplicationWithCredAndReg', ( + data: GetApplicationResponse, + credentials = [], + registrations = [] +) => { + const applicationResponse: GetApplicationResponse = data + + cy.intercept('GET', `**/api/v2/applications/${data.id}`, { + statusCode: 200, + body: applicationResponse + }).as('getApplication') + + const credsResponse: ListCredentialsResponse = { + data: credentials, + meta: { + page: { + total: credentials.length, + size: 10, + number: 1 + } + } + } + + cy.intercept('GET', `**/api/v2/applications/${data.id}/credentials*`, { + statusCode: 200, + body: credsResponse + }).as('getApplicationCredentials') + + const registrationsResponse: ListRegistrationsResponse = { + data: registrations, + meta: { + page: { + total: registrations.length, + size: 10, + number: 1 + } + } + } + + cy.intercept('GET', `**/api/v2/applications/${data.id}/registrations*`, { + statusCode: 200, + body: registrationsResponse + }).as('getApplicationRegistrations') +}) + +Cypress.Commands.add('mockContextualAnalytics', () => { + return cy.intercept( + 'POST', '**/api/v2/stats', { + statusCode: 200, + body: { records: [] }, + delay: 0 + }).as('getContextualAnalytics') +}) + +Cypress.Commands.add('mockProductVersionApplicationRegistration', (version, config = {}) => { return cy.intercept( 'GET', - `**/api/v2/application_registrations/service_versions/${version.id}`, { + `**/api/v2/application_registrations/product_versions/${version.id}`, { body: { auth_config: { name: 'key-auth', config: {} }, auto_approve: false, created_at: '2022-03-25T10:56:27.268Z', errors: [], id: 'fb4d83a5-ebf3-497c-b7a4-14aa152da470', - service_version: version, + product_version: version, status: 'enabled', updated_at: '2022-03-25T10:56:27.268Z', ...config } - }).as('getServiceVersionApplicationRegistration') + }).as('getProductVersionApplicationRegistration') }) Cypress.Commands.add('mockProductsCatalog', (count = 1, overrides = [], pageNum = 1, pageSize = 12) => { @@ -342,9 +439,9 @@ Cypress.Commands.add('mockProductsCatalog', (count = 1, overrides = [], pageNum }).as('productSearch') }) -Cypress.Commands.add('mockGetServicePackageDocumentBySlug', (productId, slug, options = {}) => { - const docId = uuidv4() - const revId = uuidv4() +Cypress.Commands.add('mockGetProductDocumentBySlug', (productId, slug, options = {}) => { + const docId = crypto.randomUUID() + const revId = crypto.randomUUID() const time = new Date().toISOString() const resp = { @@ -373,11 +470,11 @@ Cypress.Commands.add('mockGetServicePackageDocumentBySlug', (productId, slug, op 'GET', `**/api/v2/products/${productId}/documents/${slug}`, resp - ).as('servicePackageDocument') + ).as('productDocument') }) -Cypress.Commands.add('mockGetServicePackageDocuments', (productId) => { - const docId = uuidv4() +Cypress.Commands.add('mockGetProductDocuments', (productId) => { + const docId = crypto.randomUUID() const resp: ListDocumentsTree = { data: generateDocuments(docId), @@ -394,10 +491,10 @@ Cypress.Commands.add('mockGetServicePackageDocuments', (productId) => { 'GET', `**/api/v2/products/${productId}/documents`, resp - ).as('servicePackageDocuments') + ).as('productDocuments') }) -Cypress.Commands.add('mockGetServicePackageDocumentTree', (productId) => { +Cypress.Commands.add('mockGetProductDocumentTree', (productId) => { return cy.intercept( 'GET', `**/api/v2/products/${productId}/document_tree`, @@ -405,11 +502,11 @@ Cypress.Commands.add('mockGetServicePackageDocumentTree', (productId) => { statusCode: 304, body: {} } - ).as('ServicePackageDocumentTree') + ).as('ProductDocumentTree') }) Cypress.Commands.add('mockProductVersionSpec', (productId = '*', versionId = '*', content = JSON.stringify(petstoreJson30)) => { - const specResponse: ProductVersionSpec = { + const specResponse: ProductVersionSpecDocument = { api_type: 'openapi', content } @@ -419,7 +516,7 @@ Cypress.Commands.add('mockProductVersionSpec', (productId = '*', versionId = '*' }).as('spec') }) -Cypress.Commands.add('mockServiceOperations', (productId = '*', versionId = '*', operations = petstoreOperationsV2.operations as ProductVersionSpecOperationsOperationsInner[]) => { +Cypress.Commands.add('mockProductOperations', (productId = '*', versionId = '*', operations = petstoreOperationsV2.operations as ProductVersionSpecOperationsOperationsInner[]) => { const operationsResponse: ProductVersionSpecOperations = { api_type: 'openapi', operations: operations @@ -429,3 +526,22 @@ Cypress.Commands.add('mockServiceOperations', (productId = '*', versionId = '*', body: operationsResponse }).as('operations') }) + +/** + * Pass in the names and target values of Launch Darkly feature flags + * @param {Array} flags array of LD feature flags + * @returns {Cypress.Chainable} interceptor for chaining + */ +Cypress.Commands.add('mockLaunchDarklyFlags', (flags) => { + return cy.intercept( + 'GET', + 'https://app.launchdarkly.com/sdk/evalx/**', + (req) => { + req.continue((res) => { + for (const flag of flags) { + res.body[flag.name].value = flag.value + } + }) + } + ).as('mockLaunchDarklyFlags') +}) diff --git a/cypress/e2e/support/utils/cookieParser.js b/cypress/e2e/support/utils/cookieParser.js deleted file mode 100644 index eb1be083..00000000 --- a/cypress/e2e/support/utils/cookieParser.js +++ /dev/null @@ -1,22 +0,0 @@ -export function parse (cookieString) { - return cookieString.split(';').reduce((acc, cur) => { - const obj = cur.split('=') - const noSpaceKey = obj[0].replace(/\s+/g, '') - - acc[noSpaceKey] = { - key: obj[0], - value: obj[1] - } - - return acc - }, {}) -} - -export function stringify (cookieObject) { - return Object.keys(cookieObject).reduce((acc, cur) => { - const key = cookieObject[cur].key - const value = cookieObject[cur].value - - return acc === '' ? `${key}=${value}` : `${acc};${key}=${value}` - }, '') -} diff --git a/cypress/e2e/support/utils/generateDocuments.ts b/cypress/e2e/support/utils/generateDocuments.ts index 1ace3883..bffe4812 100644 --- a/cypress/e2e/support/utils/generateDocuments.ts +++ b/cypress/e2e/support/utils/generateDocuments.ts @@ -1,10 +1,9 @@ import { DocumentTree } from '@kong/sdk-portal-js' -import { v4 as uuidv4 } from 'uuid' export function generateDocuments (docId: any): DocumentTree[] { return [ { - id: uuidv4(), + id: crypto.randomUUID(), parent_document_id: null, slug: 'mock-document-1', title: 'Mock Document #1', @@ -12,7 +11,7 @@ export function generateDocuments (docId: any): DocumentTree[] { children: [] }, { - id: uuidv4(), + id: crypto.randomUUID(), parent_document_id: null, slug: 'mock-document-2', title: 'Mock Document #3', @@ -27,7 +26,7 @@ export function generateDocuments (docId: any): DocumentTree[] { meta: {}, children: [ { - id: uuidv4(), + id: crypto.randomUUID(), parent_document_id: docId, slug: 'child-document-1', title: 'Child Document #1', @@ -35,7 +34,7 @@ export function generateDocuments (docId: any): DocumentTree[] { children: [] }, { - id: uuidv4(), + id: crypto.randomUUID(), parent_document_id: docId, slug: 'child-document-2', title: 'Child Document #2', diff --git a/cypress/e2e/support/utils/generateProducts.ts b/cypress/e2e/support/utils/generateProducts.ts index aadb137f..cd9e9a36 100644 --- a/cypress/e2e/support/utils/generateProducts.ts +++ b/cypress/e2e/support/utils/generateProducts.ts @@ -1,4 +1,4 @@ -import { ProductCatalogIndexSource, ProductVersion, SearchResultsDataInner } from '@kong/sdk-portal-js' +import { ProductCatalogIndexSource, ProductCatalogIndexSourceLatestVersion, SearchResultsDataInner } from '@kong/sdk-portal-js' export const generateProducts = (count: number, options: Partial[] = []): SearchResultsDataInner[] => { const productsList: SearchResultsDataInner[] = [] @@ -7,15 +7,14 @@ export const generateProducts = (count: number, options: Partial { - const servicesData = [] - - for (let i = 0; i < count; i++) { - servicesData.push({ - source: { - id: 'a5afb115-025e-4da1-a013-bf05b326e0a5' + i, - created_at: '2020-08-25T16:14:52.450Z', - updated_at: '2020-08-25T16:14:52.450Z', - name: 'barAPI' + i, - description: null, - documents: [], - versions: [ - { - id: 'a41041e4-d324-43c8-977a-ad68f1839751' + i, - created_at: '2020-08-25T16:14:54.564Z', - updated_at: '2020-08-25T16:14:54.564Z', - version: 'v2' - } - ], - ...options[i] || {} - } - }) - } - - return servicesData -} - -export default generateServicePackages diff --git a/cypress/e2e/tsconfig.json b/cypress/e2e/tsconfig.json new file mode 100644 index 00000000..a43bf702 --- /dev/null +++ b/cypress/e2e/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "allowJs": true, + "types": [ + "node", + "cypress" + ], + "resolveJsonModule": true, + "sourceMap": false, + }, + "include": [ + "./**/*.ts" + ] +} diff --git a/lefthook.yaml b/lefthook.yaml index 8b128556..fb87e800 100644 --- a/lefthook.yaml +++ b/lefthook.yaml @@ -9,12 +9,8 @@ pre-push: - merge - rebase run: yarn lint - -commit-msg: - parallel: true - commands: - commitlint: + dependencies: skip: - merge - rebase - run: yarn commitlint --edit + run: ./.github/scripts/pin-version diff --git a/package.json b/package.json index 5e395808..eef12a15 100644 --- a/package.json +++ b/package.json @@ -8,64 +8,81 @@ "dev": "vite", "serve": "vite preview", "build": "vite build --mode production", - "lint": "eslint --ext .js,.ts,.vue --ignore-path .gitignore --fix src", + "build:analyze": "BUILD_VISUALIZER=true vite build --mode production", + "lint": "eslint --ext .js,.ts,.vue --ignore-path .gitignore src", + "lint:fix": "yarn lint --fix", "commit": "cz", "build:watch": "vite build --watch", "build:watch:dev": "vite build --watch --mode development --minify false", - "test": "yarn test:e2e", + "test": "yarn lint && yarn test:e2e", "test:e2e": "concurrently --kill-others \"yarn build:watch\" \"cypress open -C cypress.config.js --e2e -b chrome\" \"node cypress.server.mjs \"", - "test:e2e:ci": "concurrently --success first --kill-others \"yarn build && DEBUG=cypress:server cypress run -C cypress.config.js --e2e -b chrome\" \"node cypress.server.mjs \"" + "test:e2e:ci": "concurrently --success first --kill-others \"yarn build && DEBUG=cypress:server cypress run -C cypress.config.js --e2e -b chrome\" \"node cypress.server.mjs \"", + "typecheck": "vue-tsc -p './tsconfig.json' --noEmit", + "typecheck:tests": "vue-tsc -p './cypress/e2e/tsconfig.json' --noEmit", + "semantic-release": "semantic-release" + }, + "optionalDependencies": { + "launchdarkly-js-client-sdk": "3.1.3" }, "dependencies": { - "@kong-ui-public/copy-uuid": "^0.3.15", - "@kong-ui-public/document-viewer": "^0.5.18", - "@kong-ui-public/spec-renderer": "^0.7.4", - "@kong/kong-auth-elements": "2.0.0", - "@kong/kongponents": "8.60.1", - "@kong/sdk-portal-js": "0.0.1-beta.15", - "@xstate/vue": "^2.0.0", + "@kong-ui-public/analytics-chart": "0.8.31", + "@kong-ui-public/analytics-metric-provider": "1.1.22", + "@kong-ui-public/analytics-utilities": "0.7.1", + "@kong-ui-public/copy-uuid": "1.1.5", + "@kong-ui-public/document-viewer": "0.10.5", + "@kong-ui-public/spec-renderer": "0.11.28", + "@kong/kong-auth-elements": "2.8.0", + "@kong/kongponents": "8.116.2", + "@kong/sdk-portal-js": "2.1.0", + "@xstate/vue": "2.0.0", "axios": "0.27.2", - "date-fns": "2.29.3", - "js-yaml": "3.14.1", - "markdown-it": "12.3.2", - "markdown-it-anchor": "5.3.0", - "markdown-it-table-of-contents": "0.6.0", - "markdown-it-toc-done-right": "4.2.0", - "pinia": "^2.0.33", - "vite": "^4.2", - "vue": "^3.2.47", - "vue-router": "^4.1.6", - "xstate": "4.37.0" + "date-fns": "2.30.0", + "dotenv": "16.3.1", + "js-yaml": "4.1.0", + "pinia": "2.1.3", + "vue": "3.3.4", + "vue-router": "4.2.1", + "xstate": "4.38.0" }, "devDependencies": { - "@commitlint/cli": "^17.6.3", - "@commitlint/config-conventional": "^17.6.3", - "@typescript-eslint/eslint-plugin": "5.54.1", - "@typescript-eslint/parser": "5.54.1", - "@vitejs/plugin-vue": "^4.0.0", - "@vitejs/plugin-vue-jsx": "^2.1.1", - "@vue/compiler-sfc": "^3.2.47", - "@vue/eslint-config-standard": "5.1.2", - "@vue/eslint-config-typescript": "5.1.0", - "commitizen": "^4.3.0", - "concurrently": "7.6.0", - "cypress": "12.11.0", - "cypress-terminal-report": "4.1.3", - "cz-conventional-changelog": "^3.3.0", - "eslint": "^8.35.0", - "eslint-plugin-cypress": "2.12.1", - "eslint-plugin-import": "2.27.5", + "@commitlint/cli": "17.7.1", + "@commitlint/config-conventional": "17.7.0", + "@semantic-release/changelog": "6.0.3", + "@semantic-release/git": "10.0.1", + "@typescript-eslint/eslint-plugin": "5.62.0", + "@typescript-eslint/parser": "5.62.0", + "@vitejs/plugin-vue": "4.3.1", + "@vitejs/plugin-vue-jsx": "3.0.1", + "@vue/compiler-sfc": "3.3.4", + "@vue/eslint-config-standard": "8.0.1", + "@vue/eslint-config-typescript": "11.0.3", + "autoprefixer": "10.4.14", + "commitizen": "4.3.0", + "concurrently": "8.2.0", + "cypress": "12.17.1", + "cypress-split": "1.3.8", + "cypress-terminal-report": "5.3.2", + "cz-conventional-changelog": "3.3.0", + "druid.d.ts": "0.12.2", + "eslint": "8.47.0", + "eslint-plugin-cypress": "2.14.0", + "eslint-plugin-import": "2.28.0", "eslint-plugin-node": "11.1.0", - "eslint-plugin-portal-vue": "link:./eslint-plugin-portal-vue", - "eslint-plugin-promise": "4.3.1", - "eslint-plugin-standard": "4.1.0", - "eslint-plugin-vue": "^9.9.0", - "express": "^4.18.2", - "lefthook": "^1.4.0", - "sass": "1.58.3", - "tailwindcss": "1.9.6", + "eslint-plugin-portal-vue": "file:./eslint-plugin-portal-vue", + "eslint-plugin-promise": "6.1.1", + "eslint-plugin-standard": "5.0.0", + "eslint-plugin-vue": "9.17.0", + "express": "4.18.2", + "lefthook": "1.4.1", + "openapi-types": "12.1.3", + "rollup-plugin-visualizer": "5.9.2", + "sass": "1.66.1", + "semantic-release": "21.1.1", + "tailwindcss": "3.3.2", "typescript": "4.9.5", - "vite-svg-loader": "^3.6.0" + "vite": "4.4", + "vite-svg-loader": "4.0.0", + "vue-tsc": "1.8.4" }, "config": { "commitizen": { @@ -77,8 +94,17 @@ "last 2 versions", "not dead" ], + "engines": { + "npm": "please-use-yarn", + "node": ">=18.16.0 < 19", + "yarn": ">=1.22.19" + }, "volta": { - "node": "16.19.0", - "yarn": "1.22.17" + "node": "18.16.0", + "yarn": "1.22.19" + }, + "repository": { + "type": "git", + "url": "https://github.com/Kong/konnect-portal.git" } } diff --git a/postcss.config.js b/postcss.config.js index b1513f46..8f921f1d 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,7 +1,8 @@ - module.exports = { - plugins: [ - require('tailwindcss')('tailwind.config.js'), - require('autoprefixer')() - ] + plugins: { + tailwindcss: { + config: './tailwind.config.js' + }, + autoprefixer: {} + } } diff --git a/src/App.vue b/src/App.vue index ca30db07..9ddceaae 100644 --- a/src/App.vue +++ b/src/App.vue @@ -27,16 +27,16 @@ diff --git a/src/components/ErrorWrapper.vue b/src/components/ErrorWrapper.vue index 5c70f4ea..7f4bc527 100644 --- a/src/components/ErrorWrapper.vue +++ b/src/components/ErrorWrapper.vue @@ -28,7 +28,9 @@ diff --git a/src/components/ViewSpecModal.vue b/src/components/ViewSpecModal.vue index e58f438e..bad3e7ab 100644 --- a/src/components/ViewSpecModal.vue +++ b/src/components/ViewSpecModal.vue @@ -2,7 +2,7 @@