From db368a66e75d300453c45073e219a396ffdddeb9 Mon Sep 17 00:00:00 2001 From: Marco Zille <marco.zille@gmail.com> Date: Tue, 13 Aug 2024 16:36:22 +0200 Subject: [PATCH] Added todos_vue_application feature flag Instead of interweaving the old todos app on `/dashboard/todos` with the new Vue app, we create a new route `/dashboard/todos/vue` which is a little more green field. This will allow us to work without the CSS and JS tech-debt of the old page. Once the implementation of `/dashboard/todos/vue` is a little more progressed we can feature flag it on the route level. But in the mean time it's also nice that people which have the FF enabled, can just navigate to the old route as well. Follow-up steps would be switching out the route based on the FF in the nav as well. Changelog: added --- .../pages/dashboard/todos/vue/index.js | 3 ++ .../todos/components/todos_app.vue | 5 ++++ app/assets/javascripts/todos/index.js | 17 +++++++++++ app/controllers/dashboard/todos_controller.rb | 4 +++ .../todos/_user_has_no_todos.html.haml | 8 ++++++ app/views/dashboard/todos/index.html.haml | 9 +----- app/views/dashboard/todos/vue.html.haml | 17 +++++++++++ .../wip/todos_vue_application.yml | 9 ++++++ config/routes/dashboard.rb | 1 + .../dashboard/todos_controller_spec.rb | 28 ++++++++++++++++++- 10 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/pages/dashboard/todos/vue/index.js create mode 100644 app/assets/javascripts/todos/components/todos_app.vue create mode 100644 app/assets/javascripts/todos/index.js create mode 100644 app/views/dashboard/todos/_user_has_no_todos.html.haml create mode 100644 app/views/dashboard/todos/vue.html.haml create mode 100644 config/feature_flags/wip/todos_vue_application.yml diff --git a/app/assets/javascripts/pages/dashboard/todos/vue/index.js b/app/assets/javascripts/pages/dashboard/todos/vue/index.js new file mode 100644 index 000000000000..3829b9845dff --- /dev/null +++ b/app/assets/javascripts/pages/dashboard/todos/vue/index.js @@ -0,0 +1,3 @@ +import initTodosApp from '~/todos'; + +initTodosApp(); diff --git a/app/assets/javascripts/todos/components/todos_app.vue b/app/assets/javascripts/todos/components/todos_app.vue new file mode 100644 index 000000000000..282d3173b011 --- /dev/null +++ b/app/assets/javascripts/todos/components/todos_app.vue @@ -0,0 +1,5 @@ +<script> +export default {}; +</script> + +<template><div></div></template> diff --git a/app/assets/javascripts/todos/index.js b/app/assets/javascripts/todos/index.js new file mode 100644 index 000000000000..6bd24f65d3fb --- /dev/null +++ b/app/assets/javascripts/todos/index.js @@ -0,0 +1,17 @@ +import Vue from 'vue'; +import TodosApp from './components/todos_app.vue'; + +export default () => { + const el = document.getElementById('js-todos-app-root'); + + if (!el) { + return false; + } + + return new Vue({ + el, + render(createElement) { + return createElement(TodosApp); + }, + }); +}; diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index b1a8ac351bf9..d06d053a3d11 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -22,6 +22,10 @@ def index @allowed_todos = ::Todos::AllowedTargetFilterService.new(@todos, current_user).execute end + def vue + redirect_to(dashboard_todos_path, status: :found) unless Feature.enabled?(:todos_vue_application, current_user) + end + def destroy todo = current_user.todos.find(params[:id]) diff --git a/app/views/dashboard/todos/_user_has_no_todos.html.haml b/app/views/dashboard/todos/_user_has_no_todos.html.haml new file mode 100644 index 000000000000..fa383ecba1f0 --- /dev/null +++ b/app/views/dashboard/todos/_user_has_no_todos.html.haml @@ -0,0 +1,8 @@ += render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-todos-md.svg', + title: s_("Todos|Your To-Do List shows what to work on next")) do |c| + + - c.with_description do + %p + = (s_("Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List.") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe + %p + = s_("Todos|It's how you always know what to work on next.") diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index ee92fd857749..4bc7e7c5f29e 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -114,11 +114,4 @@ = link_to s_("Todos|Do you want to remove the filters?"), todos_filter_path(without: [:project_id, :author_id, :type, :action_id]) - else - = render Pajamas::EmptyStateComponent.new(svg_path: 'illustrations/empty-todos-md.svg', - title: s_("Todos|Your To-Do List shows what to work on next")) do |c| - - - c.with_description do - %p - = (s_("Todos|When an issue or merge request is assigned to you, or when you receive a %{strongStart}@mention%{strongEnd} in a comment, this automatically triggers a new item in your To-Do List.") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe - %p - = s_("Todos|It's how you always know what to work on next.") + = render 'dashboard/todos/user_has_no_todos' diff --git a/app/views/dashboard/todos/vue.html.haml b/app/views/dashboard/todos/vue.html.haml new file mode 100644 index 000000000000..a4e741166931 --- /dev/null +++ b/app/views/dashboard/todos/vue.html.haml @@ -0,0 +1,17 @@ +- page_title _("To-Do List") + += render_two_factor_auth_recovery_settings_check += render_dashboard_ultimate_trial(current_user) + += render_if_exists 'shared/dashboard/saml_reauth_notice', + groups_requiring_saml_reauth: todo_groups_requiring_saml_reauth(@todos) + +- add_page_specific_style 'page_bundles/todos' +- add_issuable_stylesheet +- user_has_todos = current_user.todos.any? + +- if user_has_todos + = render ::Layouts::PageHeadingComponent.new(_('To-Do List')) + #js-todos-app-root +- else + = render 'dashboard/todos/user_has_no_todos' diff --git a/config/feature_flags/wip/todos_vue_application.yml b/config/feature_flags/wip/todos_vue_application.yml new file mode 100644 index 000000000000..c06f58f74d68 --- /dev/null +++ b/config/feature_flags/wip/todos_vue_application.yml @@ -0,0 +1,9 @@ +--- +name: todos_vue_application +feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/464069 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/162587 +rollout_issue_url: +milestone: '17.4' +group: group::personal productivity +type: wip +default_enabled: false diff --git a/config/routes/dashboard.rb b/config/routes/dashboard.rb index a9b4582a1a4a..a78775f9afef 100644 --- a/config/routes/dashboard.rb +++ b/config/routes/dashboard.rb @@ -16,6 +16,7 @@ resources :todos, only: [:index, :destroy] do collection do + get :vue delete :destroy_all patch :bulk_restore end diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index b66ad8f1e3c2..9f5bd1a1a56b 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Dashboard::TodosController do +RSpec.describe Dashboard::TodosController, feature_category: :notifications do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, developers: user) } let_it_be(:author) { create(:user) } @@ -157,6 +157,32 @@ end end + describe 'GET #vue' do + context 'with todos_vue_application on' do + before do + stub_feature_flags(todos_vue_application: true) + end + + it 'renders 200' do + get :vue + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'with todos_vue_application off' do + before do + stub_feature_flags(todos_vue_application: false) + end + + it 'redirects to #index' do + get :vue + + expect(response).to redirect_to dashboard_todos_path + end + end + end + describe 'PATCH #restore' do let(:todo) { create(:todo, :done, user: user, project: project, author: author) } -- GitLab