diff --git a/.eslintrc.yml b/.eslintrc.yml index b1a65df946a..b6abb574e19 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -107,3 +107,7 @@ overrides: import/no-nodejs-modules: off filenames/match-regex: off no-console: off + - files: + - '*.stories.js' + rules: + filenames/match-regex: off diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index dfd595c2696..199a92d1a25 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -2,6 +2,10 @@ - source scripts/utils.sh - run_timed_command "retry yarn install --frozen-lockfile" +.storybook-yarn-install: &storybook-yarn-install + - source scripts/utils.sh + - run_timed_command "retry yarn run storybook:install --frozen-lockfile" + .compile-assets-base: extends: - .default-retry @@ -80,6 +84,15 @@ update-yarn-cache: script: - *yarn-install +update-storybook-yarn-cache: + extends: + - .default-retry + - .storybook-yarn-cache-push + - .shared:rules:update-cache + stage: prepare + script: + - *storybook-yarn-install + .frontend-fixtures-base: extends: - .default-retry @@ -344,3 +357,29 @@ startup-css-check as-if-foss: needs: - job: "compile-test-assets as-if-foss" - job: "rspec frontend_fixture as-if-foss" + +.compile-storybook-base: + extends: + - .frontend-test-base + - .storybook-yarn-cache + script: + - *yarn-install # storybook depends on the global webpack config, so we must install global deps. + - *storybook-yarn-install + - yarn run storybook:build + +compile-storybook: + extends: + - .compile-storybook-base + - .frontend:rules:default-frontend-jobs + artifacts: + name: storybook + expire_in: 31d + when: always + paths: + - storybook/public + +compile-storybook as-if-foss: + extends: + - .compile-storybook-base + - .as-if-foss + - .frontend:rules:default-frontend-jobs-as-if-foss diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index ba49ddfce9d..fbe147bd39e 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -88,6 +88,16 @@ <<: *assets-cache policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up. +.storybook-node-modules-cache: &storybook-node-modules-cache + key: "storybook-node-modules-${NODE_ENV}-v1" + paths: + - storybook/node_modules/ + policy: pull + +.storybook-node-modules-cache-push: &storybook-node-modules-cache-push + <<: *storybook-node-modules-cache + policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up. + .rubocop-cache: &rubocop-cache key: "rubocop-v1" paths: @@ -181,6 +191,14 @@ - *node-modules-cache-push - *assets-cache-push +.storybook-yarn-cache: + cache: + - *storybook-node-modules-cache + +.storybook-yarn-cache-push: + cache: + - *storybook-node-modules-cache-push + .use-pg11: image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2.patched-golang-1.16-git-2.31-lfs-2.9-chrome-89-node-14.15-yarn-1.22-postgresql-11-graphicsmagick-1.3.36" services: diff --git a/.gitlab/ci/pages.gitlab-ci.yml b/.gitlab/ci/pages.gitlab-ci.yml index b6d4b0ef11d..89ce31b5bea 100644 --- a/.gitlab/ci/pages.gitlab-ci.yml +++ b/.gitlab/ci/pages.gitlab-ci.yml @@ -8,12 +8,14 @@ pages: - coverage-frontend - karma - compile-production-assets + - compile-storybook script: - mv public/ .public/ - mkdir public/ - mv coverage/ public/coverage-ruby/ || true - mv coverage-frontend/ public/coverage-frontend/ || true - mv coverage-javascript/ public/coverage-javascript/ || true + - mv storybook/public public/storybook || true - cp .public/assets/application-*.css public/application.css || true - cp .public/assets/application-*.css.gz public/application.css.gz || true artifacts: diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index 8fded701d65..c8731e87107 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -251,6 +251,22 @@ static-analysis as-if-foss: - .static-analysis:rules:as-if-foss - .as-if-foss +zeitwerk-check: + extends: + - .rails-cache + - .default-before_script + - .rails:rules:ee-and-foss-unit + variables: + BUNDLE_WITHOUT: "" + SETUP_DB: "false" + needs: [] + stage: test + script: + - sed -i -e "s/config\.autoloader = :classic/config\.autoloader = :zeitwerk/" config/application.rb + - RAILS_ENV=test bundle exec rake zeitwerk:check + - RAILS_ENV=development bundle exec rake zeitwerk:check + - RAILS_ENV=production bundle exec rake zeitwerk:check + rspec migration pg12: extends: - .rspec-base-pg12 diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js index 0c3f273fec7..f7e3b12297e 100644 --- a/app/assets/javascripts/search/store/actions.js +++ b/app/assets/javascripts/search/store/actions.js @@ -30,7 +30,7 @@ export const fetchProjects = ({ commit, state }, search) => { if (groupId) { // TODO (https://gitlab.com/gitlab-org/gitlab/-/issues/323331): For errors `createFlash` is called twice; in `callback` and in `Api.groupProjects` - Api.groupProjects(groupId, search, {}, callback); + Api.groupProjects(groupId, search, { order_by: 'similarity' }, callback); } else { // The .catch() is due to the API method not handling a rejection properly Api.projects(search, { order_by: 'id' }, callback).catch(() => { diff --git a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue index 41b3b6c9a45..bed84dc5706 100644 --- a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue +++ b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue @@ -22,8 +22,16 @@ export default { required: false, default: '', }, + pronouns: { + type: String, + required: false, + default: '', + }, }, computed: { + hasPronouns() { + return this.pronouns !== null && this.pronouns.trim() !== ''; + }, isBusy() { return isUserBusy(this.availability); }, @@ -32,9 +40,18 @@ export default { diff --git a/app/assets/javascripts/user_popovers.js b/app/assets/javascripts/user_popovers.js index 21368edb6af..0e25f71fe05 100644 --- a/app/assets/javascripts/user_popovers.js +++ b/app/assets/javascripts/user_popovers.js @@ -44,6 +44,7 @@ const populateUserInfo = (user) => { bioHtml: sanitize(userData.bio_html), workInformation: userData.work_information, websiteUrl: userData.website_url, + pronouns: userData.pronouns, loaded: true, }); } diff --git a/app/assets/javascripts/vue_shared/components/todo_button.stories.js b/app/assets/javascripts/vue_shared/components/todo_button.stories.js new file mode 100644 index 00000000000..db4d8724a0d --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/todo_button.stories.js @@ -0,0 +1,23 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import TodoButton from './todo_button.vue'; + +export default { + component: TodoButton, + title: 'vue_shared/components/todo_button', +}; + +const Template = (args, { argTypes }) => ({ + components: { TodoButton }, + props: Object.keys(argTypes), + template: '', +}); + +export const Default = Template.bind({}); +Default.argTypes = { + isTodo: { + description: 'True if to-do is unresolved (i.e. not "done")', + control: { type: 'boolean' }, + }, + click: { action: 'clicked' }, +}; diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue index deac24d2270..f387f8ca128 100644 --- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue +++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue @@ -72,7 +72,11 @@ export default {