From 0fccb7dacd1e338b6a7db409246dc5669db3ac6e Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:44:10 +0530 Subject: [PATCH] feat: stage edits to published articles as drafts (#14842) --- .../api/v1/accounts/articles_controller.rb | 24 ++- .../HelpCenter/ArticleCard/ArticleCard.vue | 51 ++++- .../ArticleEditorPage/ArticleDiffPanel.vue | 173 +++++++++++++++++ .../Pages/ArticleEditorPage/ArticleEditor.vue | 82 ++++++-- .../ArticleEditorPage/ArticleEditorHeader.vue | 179 ++++++++++++++++-- .../ArticlePendingChangesPopover.vue | 132 +++++++++++++ .../Pages/ArticlePage/ArticleList.vue | 54 +++++- .../Pages/ArticlePage/ArticlesPage.vue | 51 ++++- .../dashboard/helper/articleDiffHelper.js | 172 +++++++++++++++++ .../helper/specs/articleDiffHelper.spec.js | 170 +++++++++++++++++ .../dashboard/i18n/locale/en/helpCenter.json | 24 +++ .../pages/PortalsArticlesEditPage.vue | 55 +++++- .../modules/helpCenterArticles/actions.js | 26 +++ .../helpCenterArticles/specs/action.spec.js | 95 ++++++++++ .../shared/helpers/MessageFormatter.js | 7 +- .../helpers/specs/MessageFormatter.spec.js | 9 + app/models/article.rb | 2 + .../accounts/articles/_article.json.jbuilder | 2 + ...623000000_add_draft_columns_to_articles.rb | 6 + db/schema.rb | 2 + .../v1/accounts/articles_controller_spec.rb | 23 +++ 21 files changed, 1280 insertions(+), 59 deletions(-) create mode 100644 app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleDiffPanel.vue create mode 100644 app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticlePendingChangesPopover.vue create mode 100644 app/javascript/dashboard/helper/articleDiffHelper.js create mode 100644 app/javascript/dashboard/helper/specs/articleDiffHelper.spec.js create mode 100644 db/migrate/20260623000000_add_draft_columns_to_articles.rb diff --git a/app/controllers/api/v1/accounts/articles_controller.rb b/app/controllers/api/v1/accounts/articles_controller.rb index 4a8363fdd..439ba3e31 100644 --- a/app/controllers/api/v1/accounts/articles_controller.rb +++ b/app/controllers/api/v1/accounts/articles_controller.rb @@ -30,8 +30,8 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController end def update - @article.update!(article_params) if params[:article].present? - render json: { error: @article.errors.messages }, status: :unprocessable_entity and return unless @article.valid? + persist_article_changes if params[:article].present? + render json: { message: @article.errors.full_messages.to_sentence }, status: :unprocessable_entity and return unless @article.valid? end def destroy @@ -67,12 +67,26 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController @portal ||= Current.account.portals.find_by!(slug: params[:portal_id]) end + # Draft-only autosaves must not bump the public-facing updated_at, so write + # them with update_columns (which skips the timestamp). update_columns also + # skips validations, so assign and validate first to avoid persisting content + # that exceeds the column length limit. + def persist_article_changes + keys = article_params.to_h.keys + if keys.any? && (keys - %w[draft_title draft_content]).empty? + @article.assign_attributes(article_params) + @article.update_columns(article_params.to_h) if @article.valid? # rubocop:disable Rails/SkipsModelValidations + else + @article.update!(article_params) + end + end + def article_params params.require(:article).permit( :title, :slug, :position, :content, :description, :category_id, :author_id, :associated_article_id, :status, - :locale, meta: [:title, - :description, - { tags: [] }] + :locale, :draft_title, :draft_content, meta: [:title, + :description, + { tags: [] }] ) end diff --git a/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue b/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue index 564888f0d..4d0cd0c71 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue @@ -1,5 +1,5 @@ + + diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue index 59c710a37..6540b6460 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue @@ -1,6 +1,6 @@